抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

事情起因

由于客户需求的原因,需要做一个wx小程序的滑动验证的功能,然而在网上查阅许多资料后,发现这是一件很费劲的事情。相关的借鉴较少,即便参照某些教程,真机调试会有相当程度的卡顿问题,以及网络图片无法加载等等各种问题。谨以此来让后来者少走些弯路吧。

项目地址

开发过程以及一些问题

大致的思路是:使用两张画布(canvas),一张画出扣除滑块的背景,一张用来画出滑块,其中第一张画布使用绝对布局,第二张画布使用相对(默认)布局,这样两张画布就能层叠到一起,并且滑块在背景之上,由于第二张画布默认布局,接下来添加控件就能在其之下继续添加。

使用方法概述

此项目相当于开发了一个组件(官方文档搜索conponments),有相当详细的使用教程。在此不再赘述,对于此项目,只需在xml界面引入

1
<jigsaw bindmyevent="myEventListener"></jigsaw
  • 它有两个如下属性,你只需要在jigsaw标签内使用即可,默认为300x150尺寸,不建议去设置它的值,因为可能会涉及到一些css样式的修改。
1
2
3
4
properties: {
canvasWidth: Number,
canvasHeight: Number
},
  • 事件名为:myevent,在页面js中配置监听事件后,只会在滑块成功时触发,且只设置了一个返回值result,为布尔类型。个人觉得已经足够了。添加更多返回值,请在jigsaw.js中找到以下位置:
1
2
3
4
5
6
if (limit < 3) {
var myEventDetail = {
"result": true
} // detail对象,提供给事件监听函数
that.triggerEvent('myevent', myEventDetail)
}

大致的使用方法就这些了,了解这些内容基本已能完全使用该组件了。如果你想深入的解读源码,以及了解该组件解决了什么问题,请继续阅读。

一些问题

  • 卡顿问题

相信很多人会找到这篇文章都是遇到了真机调试的卡顿问题,而且有相当一部分人搜索完百度后会被误导成认为“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
2
3
ins.selectComponent('.block').setStyle({
left: '{{-x}}px',
})

需要注意的两点:

1.通过此方式设置style样式之后,原xml页面通过动态绑定(““像这样)的数据将失效

2.e中包含本例的instance对象

  • 网络图片

在微信小程序中我还没发现一个能在真机上正常使用canvas加载的网络图片。由此上网上找了一个替代的方法,即:将图片缓存或下载到本地,再进行画布操作。

1
2
3
4
5
6
7
wx.getImageInfo({
src: 'https://picsum.photos/1200/600/',//这里直接就是随机的图片,不需要做随机函数
success: function(res) {
//console.log(res)
that.setData({
url: res.path,
})
  • 成功的状态

下方的slider使用wx小程序的movable-view(移动视图)做的,通过touchend事件来进行滑块验证成功与否的验证,然而搞笑的是,这个监听事件不提供x坐标(非PageX),至少我目前只在change事件发现过它。后来我放弃了,改用如下方式获取组件信息,在onLoad的时候执行一次记录slider的PageX,阿然后在touchend的监听事件中再执行一次,两者相减即为x的值(slider位移),再用此值和随机生成的滑块的位置的x值相减并取绝对值,即为误差

1
2
3
4
5
6
7
8
9
const query = this.createSelectorQuery()
query.select('#slider').boundingClientRect()
query.exec(function(res) {
//console.log(res)
that.setData({
left: res[0].left
})
//console.log(that.data.left)
})
  • 刷新的坑

前面已经提到过:wxs设置style样式后将导致原有数据绑定的样式失效,那么如果不做处理,刷新后,滑块的位置将达不到所期望的效果。解决方式很简单,通过事件的冒泡,重新设置style

1
2
3
<cover-view class='ima_wrap' bindtouchend='{{jigsaw.onEnd}}'>
<cover-image src='{{cover_image}}' bindtouchstart='onTouchStart' bindtouchend='onTouchEnd' hidden='{{cover_hidden}}'></cover-image>
</cover-view>
1
2
3
4
5
function onEnd(e,ins){
ins.selectComponent('.block').setStyle({
left: '{{-x}}px',
})
}

在你点击图片刷新的时候,会重置style的设置,重新改为动态绑定的形式。此事件的执行顺序为由内而外

此项目正确运行的截图:

评论