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>
常见问题
进度条反向旋转
原因:stroke-dasharray 变小时渲染机制导致视觉回退。
解决:确保 dashoffset 同步调整,或单向增加进度值。
缺口位置对不齐
原因:不同浏览器对 transform-origin 解析差异。
解决:显式指定 SVG transform 属性中的旋转中心。
动画卡顿
原因:主线程占用过高。
解决:使用 requestAnimationFrame,减少重绘,添加 will-change。
优化建议
计算属性缓存
避免在模板中直接计算复杂公式,使用 computed 缓存结果。
深色模式适配
使用 CSS 变量动态切换颜色。
数据防抖
接口数据频繁变化时,使用防抖处理防止动画抖动。
总结
实现不封闭圆形进度条主要依赖 SVG 描边属性。通过组件封装可复用性高。注意浏览器兼容性测试,避免过度设计。