在UniApp中构建一个既美观又实用的环形进度指示器
最近在做一个数据仪表盘项目时,遇到了一个挺有意思的需求:需要在移动端清晰、直观地展示一系列关键指标,比如任务完成度、学习进度或者健康数据。传统的条形进度条总觉得有些单调,而数字百分比又不够形象。这时候,一个设计精美的环形进度条就成了理想的选择——它不仅能直观地展示比例,还能在有限的屏幕空间内融入品牌色彩和设计语言,提升整体界面的质感。
UniApp作为跨端开发的利器,其内置的Canvas组件为我们实现自定义图形绘制提供了可能。但直接操作Canvas API去画一个圆环,对于不少开发者来说,可能觉得有些繁琐,尤其是还要考虑不同屏幕的适配、动态更新以及性能问题。因此,封装一个高可复用、易配置的环形进度条组件,就成了提升开发效率和项目一致性的关键一步。这篇文章,我就把自己从零搭建这样一个组件的过程、踩过的坑以及一些进阶优化思路分享给大家,无论你是刚接触UniApp的新手,还是希望优化现有组件的老手,或许都能找到一些有用的参考。
1. 核心原理:Canvas绘图基础与环形绘制剖析
在动手写代码之前,我们得先搞清楚环形进度条是怎么“画”出来的。UniApp中的Canvas与微信小程序、HTML5的Canvas API高度相似,其本质是一套指令式的绘图系统。你可以把它想象成一支画笔和一张画布,我们通过一系列命令(如移动画笔、画线、画弧)来最终形成图形。
一个环形进度条通常由三个部分构成:
- 底层背景:一个纯色的圆形,作为整个组件的基底。
- 静态轨道:一个完整的圆环,表示进度的总范围。
- 动态进度弧:根据百分比值绘制的另一段圆环,覆盖在静态轨道之上,用于指示当前进度。
绘制圆环的核心方法是 ctx.arc()。这个方法的参数决定了弧线的形态:
ctx.arc(centerX, centerY, radius, startAngle, endAngle, anticlockwise);
centerX, centerY: 圆心的坐标。radius: 圆的半径。startAngle: 起始弧度(0代表3点钟方向)。endAngle: 结束弧度。anticlockwise: 可选,是否逆时针绘制。
这里有个关键点:Canvas API中使用的角度单位是弧度,而非我们更熟悉的度数。整个圆是 2 * Math.PI 弧度。为了让进度从顶部(12点钟方向)开始,我们通常将起始弧度设置为 -Math.PI / 2。
进度弧的结束弧度则由百分比计算得出: endAngle = startAngle + (percent / 100) * 2 * Math.PI
另一个重要的属性是 ctx.setLineCap('round'),它用于设置线段端点的形状。设置为 'round' 可以让进度条的两端呈现圆润的效果,视觉上更柔和,这也是大多数现代环形进度条采用的设计。
注意:Canvas的绘制是“立即模式”,意味着你调用绘图指令时,它只是记录命令,直到调用
ctx.draw()或ctx.draw(true)(在UniApp中通常需要传递true以支持异步绘制)时,才会真正将内容渲染到画布上。这一点与SVG等“保留模式”图形不同。
2. 从零构建:可配置环形进度条组件
理解了原理,我们就可以开始封装组件了。我们的目标是创建一个名为 progress-circle 的组件,它应该高度可配置,并且开箱即用。
2.1 组件模板与属性定义
首先,我们定义组件的模板和需要接收的属性(Props)。Props是组件与外部通信的接口,决定了组件的可定制性。
<template>
<view class="progress-circle-container" :style="{width: finalSize + 'px', height: finalSize + 'px'}">
<canvas
:canvas-id="canvasId"
:style="{width: finalSize + 'px', height: finalSize + 'px'}"
disable-scroll="true"
@touchstart=""
></canvas>
<view class="slot-content">
<slot></slot>
</view>
</view>
</template>
<script>
export default {
name: 'ProgressCircle',
props: {
// 进度值,范围0-100
percent: {
type: Number,
default: 0,
validator: (value) => value >= 0 && value <= 100
},
// 环形进度条的整体尺寸(直径),单位rpx,设计稿基准宽度通常为750rpx
size: {
type: Number,
default: 200
},
// 进度条轨道的宽度,单位rpx
strokeWidth: {
type: Number,
default: 20
},
// 进度条颜色
progressColor: {
type: String,
default: '#409EFF' // 一种蓝色
},
// 轨道背景颜色
bgColor: {
type: String,
default: '#EBEDF0' // 浅灰色
},
// 画布背景颜色(圆形底衬)

7360

被折叠的 条评论
为什么被折叠?



