vue实现扇形进度
Vue 实现扇形进度条
使用 SVG 绘制扇形
SVG 提供了一种灵活的方式来绘制扇形进度条。可以通过 path 元素结合 d 属性动态生成扇形路径。
<template>
<svg width="200" height="200" viewBox="0 0 200 200">
<path
:d="getArcPath(progress)"
fill="#4CAF50"
stroke="#FFFFFF"
stroke-width="2"
/>
<text x="100" y="100" text-anchor="middle" dominant-baseline="middle">
{{ progress }}%
</text>
</svg>
</template>
<script>
export default {
props: {
progress: {
type: Number,
default: 0,
validator: (value) => value >= 0 && value <= 100,
},
},
methods: {
getArcPath(progress) {
const radius = 90;
const centerX = 100;
const centerY = 100;
const angle = (progress / 100) * 360;
const startAngle = -90;
const endAngle = startAngle + angle;
const startRad = (startAngle * Math.PI) / 180;
const endRad = (endAngle * Math.PI) / 180;
const x1 = centerX + radius * Math.cos(startRad);
const y1 = centerY + radius * Math.sin(startRad);
const x2 = centerX + radius * Math.cos(endRad);
const y2 = centerY + radius * Math.sin(endRad);
const largeArcFlag = angle > 180 ? 1 : 0;
return `M ${centerX} ${centerY} L ${x1} ${y1} A ${radius} ${radius} 0 ${largeArcFlag} 1 ${x2} ${y2} Z`;
},
},
};
</script>
使用 CSS 和 HTML 实现
CSS 的 conic-gradient 可以用于创建扇形进度条,但需要注意浏览器兼容性。

<template>
<div class="progress-container">
<div class="progress-fill" :style="fillStyle"></div>
<div class="progress-text">{{ progress }}%</div>
</div>
</template>
<script>
export default {
props: {
progress: {
type: Number,
default: 0,
validator: (value) => value >= 0 && value <= 100,
},
},
computed: {
fillStyle() {
return {
background: `conic-gradient(#4CAF50 ${this.progress}%, transparent 0%)`,
};
},
},
};
</script>
<style>
.progress-container {
width: 200px;
height: 200px;
border-radius: 50%;
position: relative;
background: #f5f5f5;
}
.progress-fill {
width: 100%;
height: 100%;
border-radius: 50%;
}
.progress-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 24px;
font-weight: bold;
}
</style>
使用 Canvas 绘制扇形
Canvas 提供了更底层的绘图能力,适合需要复杂动画的场景。

<template>
<canvas ref="canvas" width="200" height="200"></canvas>
</template>
<script>
export default {
props: {
progress: {
type: Number,
default: 0,
validator: (value) => value >= 0 && value <= 100,
},
},
mounted() {
this.drawProgress();
},
watch: {
progress() {
this.drawProgress();
},
},
methods: {
drawProgress() {
const canvas = this.$refs.canvas;
const ctx = canvas.getContext("2d");
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = 90;
const startAngle = -0.5 * Math.PI;
const endAngle = startAngle + (this.progress / 100) * 2 * Math.PI;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.arc(centerX, centerY, radius, startAngle, endAngle);
ctx.closePath();
ctx.fillStyle = "#4CAF50";
ctx.fill();
ctx.font = "24px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = "#000000";
ctx.fillText(`${this.progress}%`, centerX, centerY);
},
},
};
</script>
使用第三方库
对于更复杂的需求,可以考虑使用第三方库如 echarts 或 d3.js。
<template>
<div ref="chart" style="width: 200px; height: 200px"></div>
</template>
<script>
import * as echarts from "echarts";
export default {
props: {
progress: {
type: Number,
default: 0,
validator: (value) => value >= 0 && value <= 100,
},
},
mounted() {
this.initChart();
},
watch: {
progress() {
this.updateChart();
},
},
methods: {
initChart() {
this.chart = echarts.init(this.$refs.chart);
this.updateChart();
},
updateChart() {
const option = {
series: [
{
type: "pie",
radius: ["70%", "90%"],
avoidLabelOverlap: false,
label: {
show: true,
position: "center",
formatter: `${this.progress}%`,
fontSize: 24,
fontWeight: "bold",
},
data: [
{ value: this.progress, itemStyle: { color: "#4CAF50" } },
{ value: 100 - this.progress, itemStyle: { color: "#f5f5f5" } },
],
},
],
};
this.chart.setOption(option);
},
},
};
</script>
动画效果
如果需要平滑的动画效果,可以使用 requestAnimationFrame 或 CSS 过渡。
// 在 SVG 或 Canvas 方法中添加动画
animateProgress(targetProgress) {
const duration = 1000; // 动画时长
const startTime = performance.now();
const startProgress = this.progress;
const animate = (currentTime) => {
const elapsedTime = currentTime - startTime;
const progress = Math.min(elapsedTime / duration, 1);
this.progress = startProgress + (targetProgress - startProgress) * progress;
if (progress < 1) {
requestAnimationFrame(animate);
}
};
requestAnimationFrame(animate);
}
以上方法可以根据具体需求选择,SVG 适合简单场景,Canvas 适合复杂动画,第三方库适合快速实现高级功能。






