小程序实践:基础内容之progress组件,及如何自定义实现一个环形进度条?

2020-04-01 10:57:43 浏览数 (1)

目录

代码语言:javascript复制
1)主要属性2)示例代码与最佳实践
相关问题:
1)如何实现一个下载文件并显示动态进度条的功能?2)progress已选进度条如何设置圆角?3)已经加载完的进度条progress怎么点击某个按钮让它重新加载呢?4)能否实现一个圆环形进度条呢?5)progress 右边的进度百分比数字的颜色怎么设置呢?6)progress组件右侧的百分比文字,与左边离得太近了,可否增加一个边距?

本文8475字,阅读9分钟,实践40分钟

文 / 石桥码农

progress是进度条组件。

1)主要属性

progress组件的主要属性有:

progress进度条组件是一个很完备的组件了,不需要修改,就可以大部分场景需求。有两点需要注意:

a)前景色activeColor

默认是与小程序中success图标的颜色是相同的,都是“#09BB07”。虽然小程序框架给了开发者修改的自由,但是这个颜色并不能随便修改。程序中的设计风格要保持一致性,在其它地方,“#09BB07”这个颜色表示完成,在进度条里也应该作为前景完成色。如果想修改,所有地方都要修改。

在这张图中共有五个颜色,分别用作小程序中五类信息的颜色。同类信息保持颜色的一致性,有助于向用户提供清晰明确、主次分明的互动界面。

b)动画启动模式active-mode

这个属性默认为“backwards”,这是不合适的。一个进度条往往指示一件事情的进度,所以最好的动画启动模式是“forwards”,即每次从上次结束处开始。

在启用progress的active动画后,每走一段都是一段动画,每段动画都是基于css的动画绘制,都有时间。属性duration用于标识行走1%需要花费的时间,默认值为30毫秒。这个值越大,动画越细腻。

用于设计的标准屏幕宽度为375px,人类眼睛的动画觉察阀值是200毫秒,以默认值30毫秒走掉1%计算,200毫秒会走掉大约25px。这个值不能大了,再大的话动画看起来就不流畅,有卡顿。30毫秒可以视为是一个在体验上可被允许的最小值。但也不可设置过大,设置大了会影响性能。

2)示例代码与最佳实践

wxml:

代码语言:javascript复制
<progress bindtap="onTapProgressBar" stroke-width="2" percent="{{percentValue}}" active-mode="forwards" active show-info="{{false}}" bindactiveend="onProgressActiveEnd"/>

将宽度设置为2,启用动画,从数据源中以变量绑定动画进度,使用“forwards”作为动画启动模式,不显示百分比数字。其它颜色等,采用默认值。

js:

代码语言:javascript复制
onTapProgressBar(e){  let progress = this.data.percentValue  if (progress < 100){    progress  = 5    this.setData({percentValue:Math.min(100, progress)})  }}

这个示例的动画效果与文首的动画相似,只是为了方便单击演示,进度条宽度不同。

在progress组件中虽然没有bindtap这个事情属性,但tap事件是所有视图组件的基础事件,所以在这里也可以绑定事情句柄。在这个示例中,码农以onTapProgressBar这个单击后触发的函数模拟网络加载的进度事件。

每单击一次,进度 5,到100时停止。每次进度值变化,都附有一个动画。动画基本是连续和细腻的。但如果加载任务小,时间短,这个动画也是一扫而过,基本是看不到的。

下面看一下相关问题:

1)如何实现一个下载文件并显示动态进度条的功能?

有人在开发者社区问到这个问题,他想实现一个下载文件并显示动态进度条的功能,但看了文档发现percent这个必须要有固定的值(类似80),但进度是一直变化的,该如何让它实现动态进度条呢?

示例代码就可以满足需求。当启用active、并将active-mode设置为”forwards”后,动画就会随下载进度动起来。

通过文件下载的总大小和已完成大小,可以实时计算出percent数值。需要注意的是,percent属性是动态绑定的,每次变化后,需要使用setData触发视图更新,不然动画是看不到的。

2)progress已选进度条如何设置圆角?

代码:

代码语言:javascript复制
<progress border-radius="5" percent="20" show-info />

使用border-radius可以设置进度条外框的圆角大小,但是无法设置已选进度的圆角,即上面效果中绿色右端的圆角。

官方progress组件没有提供修改已选进度条圆角值的属性,有什么办法可以修改呢?

有人说,progress组件并不复杂,可以自己基于view组件实现一个。这也是一个办法,但若实现像progress那样功能完备的组件,没有看起来那么简单;况且,微信团队已经做好了一个,直接使用就是了,我们的目的是快速研发产品,没有必要在一个小组件上浪费太多精力。

小程序界面是基于浏览器内核渲染的,这也就是说,所有组件都是有它本身的css样式的。无奈微信开发者工具只开放了Wxml面板,屏蔽了Elements面板,没有办法直接查看progress组件的内部样式。

我们可以从微信开发者工具的本地源码中寻找办法。在下面这个文件中:

~/Library/Application Support/微信开发者工具/WeappCode/package.nw/js/vendor/dev/wx-components.css

放置的都是官方小程序组件的样式定义,其中有这样一条:

代码语言:javascript复制
.wx-progress-inner-bar {  width: 0;  height: 100%;}

它就是progress组件内部已选div的css类样式。

知道了样式类名就好办了。在我们项目中wxss文件中,添加如下样式:

代码语言:javascript复制
.wx-progress-inner-bar {  border-radius: 5px;}

给已选进度条加一个5px的圆角。看一下效果:

已经有圆角了。

progress本身有一个border-radius属性,将这个属性与上面样式中的border-radius设置成一样,就可以保证左右圆角一致。

这个方案在手机上测试,也有圆角效果。但它不是正规的路子,如果微信团队修改了内部样式类名,那么这个hack就不好用了。

但对于小微信团队和个人开发者来讲,无所谓了,能达到效果就好了,即使官方有变化,不能再用了,也不过是一个样式,不影响产品内容的展示。重要的是快速迭代,不在小问题上浪费太多时间。

3)已经加载完的进度条progress怎么点击某个按钮让它重新加载呢?

在这个使用示例中:

代码语言:javascript复制
<progress bindtap="onTapProgressBar" stroke-width="2" percent="{{percentValue}}" active-mode="forwards" active show-info="{{false}}" bindactiveend="onProgressActiveEnd"/>

当进度条完成后,直接将percentValue再镒设置为100,并不能让动画重新播放。

有人设想改变两次,借助nextTick或延时定时器分别在两个渲染周期里设置:

代码语言:javascript复制
this.setData({ percentValue: 0 });if (wx.canIUse('nextTick')) {  wx.nextTick(() => {    this.setData({ percentValue: 100 });  });} else {  setTimeout(() => {    this.setData({ percentValue: 100 });  }, 17);}

nextTick是基础2.2.3版本以上支持的,所以这位开发者用了wx.canIUse判断能不能使用这个Api。如果不能使用,则改用setTimeout设置一个延时定时器。

先将percentValue的值设置为0,过了一个渲染周期或17毫秒,再设置一次。这样就可以得到动画重新播放的效果。

其实每一次setData在底层都需要调用evaluateJavascript这个底层函数。这个函数用于逻辑层与视图层的通讯,它的执行本来就需要时间,并不是马上可以得到结果。因此,直接使用两次setData:

代码语言:javascript复制
<button bindtap="onTapReloadBtn">重新加载</button>onTapReloadBtn(e){  this.setData({percentValue:0})  this.setData({percentValue:50})}

也可以达到同样的效果:

在这里有一个问题,读者朋友们请思考一下,为什么上面setTimeout设置的延时定时器,要使用17毫秒呢?

这是因为目前小程序1秒内最大渲染60帧,每帧渲染约平均花费16.66毫秒,这是一个渲染周期最小的时间单位,17毫秒相当于延时一个nextTick的效果。

4)能否实现一个圆环形进度条呢?

官方的progress组件只支持常规场景,从左向左显示进度。那么,如何实现一个类似于这样的环形进度条呢:

可以用Canvas绘制。

使用Component创建一个自定义组件circle-progress,在组件的wxml代码里放置一个canvas:

代码语言:javascript复制
<view class='canvasBox'>  <view class='bigCircle'></view>  <view class='littleCircle'></view>  <canvas canvas-id="runCanvas" id="runCanvas" class='canvas'></canvas></view>

这个id为“runCanvas”的canvas将用于绘制两个圆圈,下面是灰色的圆,上面是绿色的圆。

在自定义组件中,通过一个percent的属性用于标识进度:

代码语言:javascript复制
properties: {  percent: {    type: Number,    value: 50,    observer: function (newVal, oldVal) {      this.draw(newVal);    }  },},

observer用于监听属性变化,当进度增加时,调用draw函数绘制新增的进度条。

在draw函数及后续调用的函数中,计算出需要绘制的弧度及使用Canvas Api arc进行绘制是关键:

代码语言:javascript复制
var num = (2 * Math.PI / 100 * c) - 0.5 * Math.PI;that.ctx2.arc(w, h, w - 8, -0.5 * Math.PI, num)

circle-progress是一个独立的组件。在使用时,先于json配置中声明对组件的引用:

代码语言:javascript复制
{  "usingComponents": {    "circle-progress": "../circle-progress/index"  }}

“circle-progress”是声明的名称。声明后,在wxml中就可以这样使用:

代码语言:javascript复制
<!-- 环形进度条 --><circle-progress id="progress1" percent="{{percentValue}}" /><button bindtap="drawProgress">redraw</button>

在js代码中模拟网络改变进度值:

代码语言:javascript复制
drawProgress(){  if (this.data.percentValue >= 100){    this.setData({      percentValue:0    })  }  this.setData({    percentValue:this.data.percentValue 10  })}

运行效果就是上面问题起始处的gif图片的效果。所有源码在文未阶段源码中可以找到,位于:

miniprogram/pages/2.1/circle-progress

这个组件实现起来不复杂,但有两点值得注意:

a)当在自定义组件中使用wx.createCanvasContext(canvasId)创建画布的上下文绘制对象时,需要在第二个参数处传递this:

代码语言:javascript复制
const ctx2 = wx.createCanvasContext(canvasId, this)

这样才是在组件中查找,不然只是在主文件中查找画布。

b)使用wx.createSelectorQuery().select(componentId)查找组件对象时,如果在自定义组件中,必须在查找前先调用一下in方法:

代码语言:javascript复制
const query = wx.createSelectorQuery().in(this)query.select('#' id).boundingClientRect((res)=>{  ...}).exec()

不然,这个组件是查找不到的。默认组件查询也仅是在主文件中查找,不涉及主文件中的子文件。

5)progress 右边的进度百分比数字的颜色怎么设置呢?

有两个方法,最简单直接的,是直接使用内联样式:

代码语言:javascript复制
<progress percent="40" stroke-width="5" show-info style="color:red"/>

另一种方法,和第2个问题解决圆角的方法类似。就是在这个样式文件中:

~/Library/Application Support/微信开发者工具/WeappCode/package.nw/js/vendor/dev/wx-components.css

找到百比比文字的样式,然后在自己的wxss文件中将其重写:

代码语言:javascript复制
.wx-progress-info {  color: red;}

现在所有progress组件的百分比文字都是红色了。

6)progress组件右侧的百分比文字,与左边离得太近了,可否增加一个边距?

就是感觉两者离得太近了,想优化一下,这也是社区上有人提的一个问题。

这个问题很简单,方法同问题5,直接修改样式就好了。并且这样的问题,涉及所有组件,最好是修改全局样式:

代码语言:javascript复制
.wx-progress-info {  color: red;  margin-left: 5px;}

一处修改,所有progress组件都有效果了。

0 人点赞