uni-app无内置环形进度条,需用插件或svg实现;svg方案核心是通过stroke-dasharray与stroke-dashoffset计算圆弧进度,注意起点旋转、平台兼容性及事件交互处理。

uni-app里没有内置环形进度条组件
uni-app 的 uni-ui 库只提供线性进度条 <uni-progress></uni-progress>,不支持环形(如 360° 圆弧、仪表盘风格)。强行用 CSS 画圆弧 + transform 做动画,容易在 iOS WebView 或小程序端失真、卡顿,尤其在低配安卓机上旋转角度计算错位,表现为进度“跳变”或“不动”。
实操建议:
- 优先用官方推荐的
uni-app插件市场方案:搜索「环形进度条」,安装高星插件如uni-rate-circle或uni-progress-circle(注意看 GitHub 更新时间和小程序兼容说明) - 若需完全可控,自己封装 SVG 版本:用
<svg></svg>+<circle></circle>+stroke-dasharray计算路径长度,通过stroke-dashoffset控制进度,比 CSS transform 更稳定 - 避免用
canvas动态绘制:小程序 Canvas 在v-for列表中复用时易内存泄漏,且 uni-app 的canvasToTempFilePath在 H5 端不触发回调
uni-app 中 SVG 环形进度条的关键参数怎么算
核心是把百分比进度转成 SVG 圆弧的 stroke-dashoffset。假设圆半径 r = 45,描边宽度 stroke-width = 8,那么圆周长 = 2 * Math.PI * r ≈ 282.74,这就是最大 stroke-dasharray 值。
示例代码逻辑(放在组件 data 或 computed 中):
computed: {
circleStyle() {
const r = 45
const circumference = 2 * Math.PI * r
const progress = this.percent // 0-100
const offset = circumference - (progress / 100) * circumference
return {
strokeDasharray: `${circumference} ${circumference}`,
strokeDashoffset: offset,
transition: 'stroke-dashoffset 0.3s ease'
}
}
}
注意点:
-
stroke-dasharray设为"总长 总长"是为了确保虚线模式能完整覆盖整圈,否则会出现“断弧” - 务必在
<circle></circle>上设置transform="rotate(-90 50 50)",让 0° 起点在顶部(否则默认从 3 点钟方向开始) - 小程序真机调试时,
style绑定对象里的transition可能失效,建议改用 class + CSS 动画控制
uni-app 各端环形进度条表现不一致的典型错误
最常踩的坑是 H5 正常、微信小程序白屏、App 端进度卡在 0% —— 这通常不是代码问题,而是平台渲染机制差异导致。
常见现象与对策:
- 微信小程序中
<svg></svg>子元素(如<circle></circle>)的style绑定不生效:改用class+ 动态 class 名,例如:class="'progress-' + Math.round(percent)",CSS 里写好所有 0–100 的偏移值 - H5 端圆弧边缘锯齿明显:给
<svg></svg>加shape-rendering="geometricPrecision",并确保父容器宽高是偶数像素 - App 端(尤其是 iOS)
transform: rotate()动画卡顿:禁用硬件加速(删掉-webkit-transform: translateZ(0)),改用animation-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1)模拟缓动 - 进度更新后视图不刷新:检查
percent是否为响应式数据(不能是const或函数返回值),且赋值时用this.percent = newValue,而非直接修改对象属性
uni-app 里怎么让环形进度条支持点击/拖拽交互
原生 SVG 不支持 @click 事件冒泡到 <circle></circle>,必须加一层透明遮罩或用 <view></view> 包裹整个 SVG 并监听 touch 事件。
实操要点:
- 不要给
<circle></circle>直接绑@touchstart:小程序中无效,H5 中可能触发多次 - 用
<view class="progress-wrapper"></view>包住 SVG,设position: relative;内部加一个<view class="mask"></view>覆盖全区域,opacity: 0+pointer-events: auto - 拖拽计算角度时,用
Math.atan2(dy, dx)而非Math.atan(),避免象限判断错误;再映射到 0–360° 后转为 0–100% 进度 - 微信小程序中
touchmove频率受限(约 30fps),建议加防抖:仅当角度变化 > 2° 时才更新percent
环形进度条真正的难点不在画圆,而在各端对 SVG 属性、CSS 动画、事件绑定的支持程度不一。同一个 stroke-dashoffset 表达式,在 H5 是流畅动画,在小程序里可能得拆成 20 个预设 class 才稳。










