Vue2.x 使用 SVG 实现不封闭圆形进度条及组件封装
引言
在 Vue2.x 项目中实现不封闭圆形进度条是常见的前端需求。本文介绍基于 SVG 的实现方案,通过组件化封装满足灵活配置的需求。
技术原理
不封闭圆形进度条概念
不封闭圆形进度条即带有缺口的圆环。技术上主要通过 SVG 的描边属性控制实线与空白区域的比例。
实现方式对比
- SVG 方案:使用
<circle>标签配合stroke-dasharray和stroke-dashoffset属性。可控性强,无外部依赖。 - Canvas 方案:底层绘图,代码量大,需处理高清屏像素比。
- CSS 方案:利用
border-radius或conic-gradient,灵活性较差。 推荐使用手写 SVG 方案,符合 Vue 组件化思想。
核心技术
SVG 描边属性
stroke-dasharray:定义虚线模式(实线长度,空白长度)。stroke-dashoffset:定义起始偏移量,控制缺口位置。stroke-linecap:设置端点样式(round 为圆角)。
数据驱动
将计算后的属性绑定到 Vue 响应式数据上。当进度变化时,自动更新 SVG 属性。
路径计算
若需更复杂的缺口形状,可使用 <path> 结合贝塞尔曲线绘制。通过三角函数计算极坐标转笛卡尔坐标。
方案对比
SVG 优势
- 体积小,无外部依赖。
- 矢量图形,清晰度无敌。
- DOM 节点,交互性强。
- SEO 友好。
兼容性与性能
- Android 4.4+ 支持良好,旧版本需注意锯齿问题。
- 大量渲染时需优化重绘,使用
requestAnimationFrame和will-change。
组件实现
通用组件封装
封装 GapProgress 组件,支持以下 Props:
percentage:进度百分比。gap:缺口大小。size:画布大小。gradient:是否启用渐变。animation:是否开启动画。
<template>
<div :style="containerStyle">
<svg :width="size" :height="size" :viewBox="`0 0 ${size} ${size}`">
<!-- 背景圆环 -->
<circle :cx="center" :cy="center" :r="radius" fill="none" :stroke="bgColor" :stroke-width="strokeWidth" />
<!-- 进度圆环 -->
<circle :cx="center" :cy="center" :r="radius" fill="none" :stroke="progressColor" :stroke-width="strokeWidth" :stroke-dasharray="dashArray" :stroke-dashoffset="dashOffset" stroke-linecap="round" :transform="`rotate(${rotate} ${center} ${center})`" :style="transitionStyle" />
</svg>
<div v-if="$slots.default">
<slot :percentage="displayPercentage"></slot>
</div>
</div>
</template>
<script>
export default {
name: 'GapProgress',
props: {
percentage: { type: Number, default: 0 },
gap: { type: Number, default: 15 },
size: { type: Number, default: 120 },
strokeWidth: { type: Number, default: 8 }
},
computed: {
center() { return this.size / 2; },
radius() { return (this.size - this.strokeWidth) / 2; },
circumference() { return 2 * Math.PI * this.radius; },
dashArray() { return `${this.progressLength}, ${this.circumference}`; },
dashOffset() { return this.gapLength / 2; }
}
};
</script>


