事情起因
由于客户需求的原因,需要做一个wx小程序的滑动验证的功能,然而在网上查阅许多资料后,发现这是一件很费劲的事情。相关的借鉴较少,即便参照某些教程,真机调试会有相当程度的卡顿问题,以及网络图片无法加载等等各种问题。谨以此来让后来者少走些弯路吧。
开发过程以及一些问题
大致的思路是:使用两张画布(canvas),一张画出扣除滑块的背景,一张用来画出滑块,其中第一张画布使用绝对布局,第二张画布使用相对(默认)布局,这样两张画布就能层叠到一起,并且滑块在背景之上,由于第二张画布默认布局,接下来添加控件就能在其之下继续添加。
使用方法概述
此项目相当于开发了一个组件(官方文档搜索conponments),有相当详细的使用教程。在此不再赘述,对于此项目,只需在xml界面引入
1 | <jigsaw bindmyevent="myEventListener"></jigsaw |
- 它有两个如下属性,你只需要在jigsaw标签内使用即可,默认为300x150尺寸,不建议去设置它的值,因为可能会涉及到一些css样式的修改。
1 | properties: { |
- 事件名为:myevent,在页面js中配置监听事件后,只会在滑块成功时触发,且只设置了一个返回值result,为布尔类型。个人觉得已经足够了。添加更多返回值,请在jigsaw.js中找到以下位置:
1 | if (limit < 3) { |
大致的使用方法就这些了,了解这些内容基本已能完全使用该组件了。如果你想深入的解读源码,以及了解该组件解决了什么问题,请继续阅读。
一些问题
- 卡顿问题
相信很多人会找到这篇文章都是遇到了真机调试的卡顿问题,而且有相当一部分人搜索完百度后会被误导成认为“canvas导致的卡顿”等等。刚开始的时候我也是这么认为的,直到我看见了下面的内容:
常见的 setData 操作错误
1. 频繁的去 setData
在我们分析过的一些案例里,部分小程序会非常频繁(毫秒级)的去
setData
,其导致了两个后果:
- Android 下用户在滑动时会感觉到卡顿,操作反馈延迟严重,因为 JS 线程一直在编译执行渲染,未能及时将用户操作事件传递到逻辑层,逻辑层亦无法及时将操作处理结果及时传递到视图层;
- 渲染有出现延时,由于 WebView 的 JS 线程一直处于忙碌状态,逻辑层到页面层的通信耗时上升,视图层收到的数据消息时距离发出时间已经过去了几百毫秒,渲染的结果并不实时;
2. 每次 setData 都传递大量新数据
由
setData
的底层实现可知,我们的数据传输实际是一次evaluateJavascript
脚本过程,当数据量过大时会增加脚本的编译执行时间,占用 WebView JS 线程,3. 后台态页面进行 setData
当页面进入后台态(用户不可见),不应该继续去进行
setData
,后台态页面的渲染用户是无法感受的,另外后台态页面去setData
也会抢占前台页面的执行。
这是来自官方文档性能篇的一段话,详细看完之后,总结起来就是,在js监听的change之类的高频率刷新的事件,应当避免使用setData设置页面数据。对于这类动画的监听操作,我找到了一个替代品:wxs响应事件,在此页面中监听事件,你可以动态的获取该组件的相关参数(e)以及通过(instance)找到页面中的每个组件的实例,并且设置其class和style属性,就像这样:
1 | ins.selectComponent('.block').setStyle({ |
需要注意的两点:
1.通过此方式设置style样式之后,原xml页面通过动态绑定(““像这样)的数据将失效
2.e中包含本例的instance对象
- 网络图片
在微信小程序中我还没发现一个能在真机上正常使用canvas加载的网络图片。由此上网上找了一个替代的方法,即:将图片缓存或下载到本地,再进行画布操作。
1 | wx.getImageInfo({ |
- 成功的状态
下方的slider使用wx小程序的movable-view(移动视图)做的,通过touchend事件来进行滑块验证成功与否的验证,然而搞笑的是,这个监听事件不提供x坐标(非PageX),至少我目前只在change事件发现过它。后来我放弃了,改用如下方式获取组件信息,在onLoad的时候执行一次记录slider的PageX,阿然后在touchend的监听事件中再执行一次,两者相减即为x的值(slider位移),再用此值和随机生成的滑块的位置的x值相减并取绝对值,即为误差
1 | const query = this.createSelectorQuery() |
- 刷新的坑
前面已经提到过:wxs设置style样式后将导致原有数据绑定的样式失效,那么如果不做处理,刷新后,滑块的位置将达不到所期望的效果。解决方式很简单,通过事件的冒泡,重新设置style
1 | <cover-view class='ima_wrap' bindtouchend='{{jigsaw.onEnd}}'> |
1 | function onEnd(e,ins){ |
在你点击图片刷新的时候,会重置style的设置,重新改为动态绑定的形式。此事件的执行顺序为由内而外
此项目正确运行的截图: