目录
代码语言: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组件都有效果了。