微信小程序之圆形进度条(自定义组件)
思路
- 使用2个canvas 一个是背景圆环,一个是彩色圆环。
- 使用setInterval 让彩色圆环逐步绘制。
在看我的文章前,必须先看 ,下面转的文章,因为本文是在它们基础上修改的.
它们的缺点为:
1.组件必须用js实例化 (如果我有一个任务列表,后面会显示每个任务的进度,每个任务都必须实例化)
2.它们js实例化时,绘图是用 px绘制,导致页面用rpx布局,组件却用px绘制.
修改后的组件
在components文件加下建立 circle组件,如图
circle.js :
/* components/circle/circle.js */ Component({ options: { multipleSlots: true // 在组件定义时的选项中启用多slot支持 }, properties: { draw: {//画板元素名称id type: String, value: 'draw', observer:function(newVal,oldVal,change){ console.log(newVal, oldVal, change); this.onreset(); //数值变化是所有重绘 } }, per:{ //百分比 通过此值转换成step type: String, value: '0', observer:function(newVal,oldVal,change){ console.log(newVal, oldVal, change); this.onreset();//数值变化是所有重绘 } }, r:{//半径 type: String, value: '50', observer:function(newVal,oldVal,change){ console.log(newVal, oldVal, change); this.onreset();//数值变化是所有重绘 } } }, data: { /* 私有数据,可用于模版渲染 */ step: 1, //用来算圆的弧度0-2 size:0, //画板大小 screenWidth:750, //实际设备的宽度 txt:0 }, methods: { /** * el:画圆的元素 * r:圆的半径 * w:圆的宽度 * 功能:画背景 */ drawCircleBg: function (el, r, w) { const ctx = wx.createCanvasContext(el,this); ctx.clearRect(0, 0, 2*r, 2*r); ctx.draw();//清空缓存内容 ctx.setLineWidth(w);// 设置圆环的宽度 ctx.setStrokeStyle('#E5E5E5'); // 设置圆环的颜色 ctx.setLineCap('round') // 设置圆环端点的形状 ctx.beginPath();//开始一个新的路径 ctx.arc(r, r, r - w, 0, 2 * Math.PI, false); //设置一个原点(110,110),半径为100的圆的路径到当前路径 ctx.stroke();//对当前路径进行描边 ctx.draw(); }, /** * el:画圆的元素 * r:圆的半径 * w:圆的宽度 * step:圆的弧度 (0-2) * 功能:彩色圆环 */ drawCircle: function (el, r, w, step) { var context = wx.createCanvasContext(el,this); context.clearRect(0, 0, 2*r, 2*r); context.draw();//清空缓存内容 // 设置渐变 var gradient = context.createLinearGradient(2 * r, r, 0); gradient.addColorStop("0", "#2661DD"); gradient.addColorStop("0.5", "#40ED94"); gradient.addColorStop("1.0", "#5956CC"); context.setLineWidth(w); context.setStrokeStyle(gradient); context.setLineCap('round') context.beginPath();//开始一个新的路径 // step 从0到2为一周 context.arc(r, r, r - w, -Math.PI / 2, step * Math.PI - Math.PI / 2, false); context.stroke();//对当前路径进行描边 step?context.draw():''; //当step为空的时候不画0% }, /** * 功能:重绘画板 */ onreset: function () { const _this = this; //获取屏幕宽度 wx.getSystemInfo({ success: function(res) { _this.setData({ screenWidth: res.windowWidth }); }, }); //初始化 const el = _this.data.draw; //画板元素 const per = _this.data.per; //圆形进度 const r = Number(_this.data.r); //圆形半径 _this.setData({ step: (2 * Number(_this.data.per)) / 100, txt: _this.data.per }); //获取屏幕宽度(并把真正的半径px转成rpx) let rpx = (_this.data.screenWidth / 750) * r; //计算出画板大小 this.setData({ size: rpx * 2 }); const w = 4;//圆形的宽度 //组件入口,调用下面即可绘制 背景圆环和彩色圆环。 _this.drawCircleBg(el + 'bg', rpx, w);//绘制 背景圆环 _this.drawCircle(el, rpx, w, _this.data.step);//绘制 彩色圆环 } }, lifetimes: { // 生命周期函数,可以为函数,或一个在methods段中定义的方法名 attached: function () { const _this = this; //获取屏幕宽度 wx.getSystemInfo({ success: function(res) { _this.setData({ screenWidth: res.windowWidth }); }, }); //初始化 const el = _this.data.draw; //画板元素 const per = _this.data.per; //圆形进度 const r = Number(_this.data.r); //圆形半径 _this.setData({ step: (2 * Number(_this.data.per)) / 100, txt: _this.data.per }); //获取屏幕宽度(并把真正的半径px转成rpx) let rpx = (_this.data.screenWidth / 750) * r; //计算出画板大小 this.setData({ size: rpx * 2 }); const w = 4;//圆形的宽度 //组件入口,调用下面即可绘制 背景圆环和彩色圆环。 _this.drawCircleBg(el + 'bg', rpx, w);//绘制 背景圆环 _this.drawCircle(el, rpx, w, _this.data.step);//绘制 彩色圆环 } } })
circle.wxml :
<!-- components/circle/circle.wxml --> <view class="circle_box" style="width:{{size}}px;height:{{size}}px"> <canvas class="circle_bg" canvas-id="{{draw}}bg" style="width:{{size}}px;height:{{size}}px"></canvas> <canvas class="circle_draw" canvas-id="{{draw}}" style="width:{{size}}px;height:{{size}}px"></canvas> <text class='circle_txt'> {{txt}}% </text> </view>
circle.json :
{ "component": true, "usingComponents": {} }
circle.wxss :
.circle_box,.circle_draw{ position: relative; } .circle_bg{position: absolute;} .circle_box{ display: flex; flex-direction: row; justify-content: center; align-items: center; } .circle_txt{ position: absolute; font-size: 28rpx; }
调用 :
在所需页面的XXX.json 先引入 组件
{ "usingComponents": { "circle": "/components/circle/circle" } }
wxml 使用组件
<circle draw='circwewle1' per = '40' r = '50'/> <circle draw='circwewle2' per = '10' r = '30'/> <circle draw='circwewle3' per = '20' r = '100'/> <circle draw='circwewle' per = '50' r = '60'/> <circle draw='circwewle' per = '90' r = '120'/> draw : 确定 canvas的id per : 进度百分比 (1-100) r: 圆的半径 (按px,最终转化成rpx)
结果:
注意,1楼网友反馈,数据更新时组件没更新,(我临时把声明周期的函数,复制了一份移动到methods中,在属性值变化是调用了一下,可以数据更新了)
转 :
https://segmentfault.com/a/1190000013219501
https://segmentfault.com/a/1190000013242747?utm_source=tag-newest
参考微信自定义组件讲解 : https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/