视频链接:
片 1
在前端网络操作是异步的,一般都需要一个进度条。在很多应用中,我们经常可以看到环形进度条,但是小程序原生的 progress 组件,是一个从左到右的方形进度条,那么我们可不可以自实现一个环形的进度条呢?
答案肯定是可以的。从原理上来讲,只要我们能够获知网络异步操作的进度,以及绘制出环形动画效果,就可以实现了。
先看一下原生的组件。
片 2
在这个代码中,show-info 代表是否在进度条右侧显示百分比文本。一般不需要显示,因为进度条本身就标明了进度。bindtap 用于绑定 tap 事件,所有可视的 view 组件都可以绑定 tap 事件,即使属性列表中没有显式标明。stroke-width 表示进度条的宽度,这是从前进方向来看是宽度,从表象看实则是高度。这个定义与 css 中的 stroke-width 类似。percent 是百分比,在 0~100 之间。active-mode 是动画停止后重新启动的模式,有两个值:backwards, 表示动画从头播;forwards,表示动画从上次结束的位置继续播放,它的默认值是 backwards,但在实践中我们一般使用 forwards。active 表示是否展示动画,与 show-info 一样,布尔属性为真,只需要列上属性就可以了。如果想显式设置为 false,需要写成 active="{{false}}"这样的形式。bindactiveend 用于绑定动画结束的事件,在动画结束时触发。
这里有两个颜色属性需要注意:activeColor 与 backgroundColor。默认情况下,activeColor 是十六进制“#09BB07”,backgroundColor 是十六进制“#EBEBEB”。小程序框架给了开发者修改的自由,但是这个颜色并不能随便使用。程序中的设计风格要保持一致性,这就涉及到应用程序的设计规范问题。
片 3
上面的网址,是微信设计规范网址。从上面的颜色规范中,可以看到#09bb07 是默认的 activeColor 颜色。第一个#09bb07 是完成色,第二个#353535 称之为 Semi,大段说明内容而且属于主要内容的,例如正文,使用这个颜色。第三个#888888,称之为 Grey,用于次要内容。第四个是链接色,第五个是警告色。
纯黑色 Black,一般用于主内容。浅灰色 Light,一般用于时间戳与表单的缺省值。
backgroundColor 默认的颜色值#EBEBEB,不在上面的列表之内。在 weui 组件库内,默认按钮的底色是#f2f2f2,这个颜色值和#ebebeb 是很接近的。在使用的时候我们要统一使用一致的颜色,表示相同的含义,在这里我们将 backgroundColor 设置为#f2f2f2。
介绍完组件的属性,接下来我们看开发中经常会遇到哪些问题。
片 4
有人在开发者社区问到这个问题,他想实现一个下载文件时显示动态进度条的功能,但看了文档后,发现 percent 这个属性必须设置固定的值,例如 80,但进度是一直变化的,该如何实现动态进度条呢?
我们前面的示例代码基本就可以这个满足需求了。当启用 active、并将 active-mode 设置为 forwards 后,动画就会随下载进度动起来。
通过文件下载的总大小和已完成大小,可以实时计算出 percent 数值。需要注意的是,percent 属性是动态绑定的,每次变化后,需要我们显式使用 setData 触发视图更新,不然动画是不动的。
片 5
在上面代码中,border-radius 属性可以设置圆角大小,默认值是 0。但 border-radius 设置的是进度条外框的圆角大小,它无法设置内部已经前进的进度条圆角。
有人说,progress 组件并不复杂,可以自己基于 view 组件实现一个。这也是一个办法,但如果实现一个像官方 progress 那样动画完备的组件,也没那么简单。况且微信团队已经做好了一个,直接使用就是了,我们的目的是快速研发产品,没有必要在一个小组件上投入太多精力。
小程序界面是基于浏览器内核渲染的,这也就是说,所有官方组件都是有它本身的 css 样式的。或许我们可以通过调试功能,查找出组建的 css 样式,直接在页面内进行样式重写。
微信开发者工具只开放了 WXML 面板,屏蔽了 Elements 面板,没有办法直接查看 progress 组件的内部样式是什么,否则我们拿到内部样式后可以重写它。
但我们可以从微信开发者工具的本地源码中寻找办法。
在本地的组件样式文件中(见上面地址),放置的是官方小程序组件的样式定义,其中.wx-progress-inner-bar 这个样式负责控制内部已经前进的进度条样式。我们只需要在页面内重写这个样式,给他加一个 border-radius 圆角就可以了(见上面代码)。
但这个方法不是正规的路子,如果微信团队修改了内部样式的类名,那么这个 hack 方法就不好用了。
但是对于小微团队和个人开发者来讲,其实无所谓,能达到页面效果就好了。即使官方有变化,也不过是一个小样式,不影响产品体验大局。重要的是快速迭代,不在小问题上浪费太多时间。
片 6
有人说,开启 active 动画后,当进度条完成以后,直接再设置一下 percent 属性的值,就可以实现。
但是这个方法行不通,直接将 percent 再设置为 100 或其他数值,并不能让动画重新播放。
有人设想改变两次 percent,借助 nextTick,或延时定时器分别在两个渲染周期里设置。nextTick 是基础库 2.2.3 版本以上支持的,所以这位作者用了 wx.canIUse 判断能不能使用这个 Api。如果不能使用,则改用 setTimeout 设置一个延时定时器(见上面代码)。
先将 percent 的值设置为 0,过了一个渲染周期,或延时 17 毫秒再设置一次。这样就可以得到动画重新播放的效果了。
其实还有简单的方法。每一次 setData 在底层都需要调用 evaluateJavascript 这个底层函数。这个函数用于逻辑层与视图层之间的通讯,它的执行本来就需要时间。因此,直接调用两次 setData 也可以达到同样的效果(见上面代码)。
连续调用两次 setData 可能看起来不是那么优雅。但有时候看起来不是那么优雅的代码,才是最简单和有效的代码。
在这里有一个问题,留给读者朋友思考一下,为什么上面 setTimeout 设置的延时定时器,要使用 17 毫秒呢?这作为一个作业,答案我们下节课揭晓。
片 7
这也是开始我们提到的问题。官方的 progress 组件只支持常规场景,从左向左显示进度。那么如何实现一个环形进度条呢?
用 css 绘制动画比较麻烦,可以用 Canvas 绘制。使用 Component 创建一个自定义组件,例如名字就叫 circle-progress,在这个组件的 WXML 代码里放置一个 Canvas 组件,并给它设置一个 id(见上面代码)。
这个 id 为 runCanvas 的 Canvas 组件,它用于绘制上面的绿色的圆。灰色的圆环,是由一个灰色的底圆(bigCircle),加一个白色的稍微小一点的圆(littleCircle)组合出来的,它是由 css 样式实现的(见上面代码)。
在自定义组件中,通过一个 percent 的属性用于标识进度(见上面代码),这个属性与官方的 progress 组件具有相同的名称,这方便我们迁移代码和减小记忆负担。observer 用于自动监听属性变化,当进度增加时,调用 draw 函数绘制新增的绿色进度条(见上面代码)。
在 draw 函数及后续调用的函数中,计算出需要绘制的弧度,及使用 Canvas 的弧度绘制 Api arc,进行绘制是实现环形效果的关键(见上面代码)。
片 8
circle-progress 是一个独立的组件。在使用时,需要先在 json 配置中声明对组件的引用。circle-progress 是声明的名称。声明后,在 wxml 中就可以把它当做标签使用了(见上面)。
在 button 触发的 js 函数中,模拟网络变化改变进度值,就可以查看到动画效果了。相关代码在本课源码中都可以找到(位于 miniprogram/pages/2.1/progress)。
大家看了源码就会知道,实现自定义组件不复杂,但有两点值得注意:
1,当在自定义组件中使用 wx.createCanvasContext 创建画布的上下文绘制对象时,需要在第二个参数处传递 this 对象(见上面代码)。这样才是在组件中查找画布,不然只是在主页面中查找——也就是在引用它的页面中查找画布了。
2,使用 wx.createSelectorQuery 创建的对象的 select 方法,以 id 查找组件对象时,如果在自定义组件中,必须在查找前,先调用一下它的 in 方法(见上面代码),把 this 对象传递进去。不然,这个组件是查找不到的。默认组件查询也仅是在主页面中查找,不会涉及主页面中的子组件。
片 9
有两个方法,最简单直接的,是直接使用内联样式(见上面代码)。
另一种方法,在第二个问题中解决圆角的时候用过了,在本地样式文件中,找到类样式的名称,然后在页面中重写(见上面代码)。重写以后,所有 progress 组件的百分比文字都是红色了。
片 10
就是感觉进度条和百分比数字,两者离得太近了,想优化一下,这是社区上有人提的一个问题。这个问题很简单,解决方法同问题五,直接修改样式就好了。并且这样的问题,涉及所有组件,最好也是修改全局的样式。
最后给大家留个作业:在问题三中,为什么 setTimeout 设置的延时定时器,要使用 17 毫秒?如果你有答案,欢迎在下面留言。
片 11
上节课作业是:从 iconfront.cn 搜索两个图标,以自定义的方式用在自己的小程序项目中。我们看一下如何实现。
好,这节课就讲到这里。这节课主要介绍了小程序组件 progress,及如何实现一个环形进度条,下节课我们介绍 rich-text 富文本组件。
2020 年 5 月 14 日