SOURCE

console 命令行工具 X clear

                    
>
console
new Vue({
    el: '#app',
    data() {
        return {
            width: 100,
            progress: 1,
            strokeWidth: 10
        }
    },
    computed: {
        rootStyle() {
            return {
                '--width': `${this.width}px`,
                '--stroke-width': `${this.strokeWidth}px`
            }
        },
        path() {
            const w = this.width
            const w2 = w / 2
            let tmp = this.progress
            if (tmp === 1) {
                tmp = tmp - 0.00001
            }
            let angle = 360 * tmp
            angle = (90 - angle) * Math.PI / 180
            x = w2 + Math.cos(angle) * w2
            y = w2 - Math.sin(angle) * w2
            const p = `M ${w2} ${w2} v ${-w2} A ${w2} ${w2} 0 1 1 ${x} ${y} L ${w2} ${w2} z`
            return p
        }
    },
    mounted() {
        this.setProgress(0.5)
    },
    methods: {
        setProgress(p) {
            const cnt = 50
            const time = 500
            const interval = time / cnt
            const step = p / cnt
            console.log(interval, step)
            let tmp = 0
            this.progress = tmp
            if (this.timer) {
                clearInterval(this.timer)
            }
            this.timer = setInterval(() => {
                tmp += step
                if (tmp >= p) {
                    tmp = p
                    clearInterval(this.timer)
                    this.timer = null
                }
                this.progress = tmp
            }, interval)
        }
    }
})
<div id="app" :style="[rootStyle]">
    <svg class="svgwrap">
        <defs>
            <clippath id="path">
                <path :d="path"></path>
            </clippath>
        </defs>
        <circle class="circle gray"></circle>
        <circle id="progress" class="circle" clip-path="url(#path)"></circle>
    </svg>
</div>
* {
     box-sizing: border-box;
     margin: 0;
     padding: 0;
}

#app {
    width: var(--width);
    height: var(--width);
    border: 1px solid black;
}

.svgwrap {
    width: 100%;
    height: 100%;
    transform: rotateX(60deg);
}

.circle {
    cx: calc(var(--width)/2);
    cy: calc(var(--width)/2);
    r: calc(var(--width)/2 - var(--stroke-width)/2);
    fill: none;
    stroke: red;
    stroke-width: var(--stroke-width);
    stroke-dasharray: 10 5;
}

.circle.gray {
    stroke: gray;
}

本项目引用的自定义外部资源