在做一个小球跟随手指移动的效果时候,由于在touchmove事件中频繁调用setData改变小球的位移实现,在开发工具和IOS平台还算流畅,但在安卓机下手机预览出现极其卡顿的交互,简直是不堪入目。
可微信web开发者工具打开 片段代码https://developers.weixin.qq.com/s/B9UHyvmo7t6t
问题根源:
setData每秒调用高达50左右造成的。 引用官方的话就是:
a、touchmove 事件从视图层(Webview)抛到逻辑层(App Service)
b、逻辑层(App Service)处理 touchmove 事件,再通过 setData 来改变 组件 的位置
一次 touchmove 的响应需要经过 2 次的逻辑层和渲染层的通信以及一次渲染,通信的耗时比较大。此外 setData 渲染也会阻塞其它脚本执行,导致了整个用户交互的动画过程会有延迟。
如何优化?
1.使用movable-view
movable-view + movable-area可实现移动效果很流畅,但是也有局限性不能满足复杂的需求,例如现在需求需要是两个小球使用两个手指能同时控制小球移动,则无法实现,还需要配合setData来实现,使用了setData必然会出现卡顿
2.推荐方案:抛弃setData,使用wxs来写交互
从基础库 2.4.4 开始支持 WXS响应事件 直接上代码,本人菜鸟,代码写的很乱:
index.js
const app = getApp() Page({ data: { balls: [1, 2, 3, 4, 5, 5, 6, 7] } }) 复制代码
index.wxml
//引入wxs文件 <wxs module="index" src="./index.wxs"></wxs> <view class='wrap' catchtouchstart='{{index.touchstart}}' catchtouchmove='{{index.touchmove}}' catchtouchend='{{index.touchend}}'> <view class="demo hide" wx:for="{{ balls }}"></view> </view> 复制代码
index.wxs
var allTouchs = [], len = 0, instances = [], instanceLen, isMoveEnd = false function reset(ownerInstance) { //重置 for (var i = 0; i < instanceLen; i++) { instances[i].setStyle({ 'transform': '', 'display': 'none' }) } } function touchstart(event, ownerInstance) { if (isMoveEnd) return //获取当前移动的手指 var bounds = event.touches, boundsLen = bounds.length allTouchs = event.touches, len = event.touches.length instances = ownerInstance.selectAllComponents('.demo'), instanceLen = instances.length for (var i = 0; i < instanceLen; i++) { var instance = instances[i], bound = bounds[i] if (i < boundsLen) { //更新 instance.disabled = false instance.identifier = bound.identifier instance.setStyle({ 'transform': 'translateX(' + bound.pageX + 'px) translateY(' + bound.pageY + 'px)', 'display': 'block' }) } else { instance.setStyle({ 'transform': '', 'display': 'none' }) instance.disabled = true instance.identifier = '' } } } function touchmove(event, ownerInstance) { //获取当前移动的手指 var bounds = event.changedTouches, boundsLen = bounds.length, bound = null, instance = null, allTouch = null for (var i = 0; i < instanceLen; i++) { instance = instances[i] for (var j = 0; j < boundsLen; j++) { bound = bounds[j] if (instance.identifier === bound.identifier) { //更新 instance.setStyle({ 'transform': 'translateX(' + bound.pageX + 'px) translateY(' + bound.pageY + 'px)', 'display': 'block' }) } } } } function touchend(event, ownerInstance) { isMoveEnd = true //获取当前移动的手指 var bounds = event.changedTouches, boundsLen = bounds.length, bound = null, instance = null, allTouch = null for (var i = 0; i < instanceLen; i++) { instance = instances[i] for (var j = 0; j < boundsLen; j++) { bound = bounds[j] if (instance.identifier === bound.identifier) { //更新 instance.setStyle({ 'transform': '', 'display': 'none' }) //移除 instances[i].disabled = true instances[i].identifier = '' } } } var tmp = instances.filter(function (item) { return !item.disabled }) if (tmp.length < 1) { //重置 reset(ownerInstance) } isMoveEnd = false } module.exports = { touchmove: touchmove, touchend: touchend, touchstart: touchstart } 复制代码
微信web开发者工具打开小程序代码片段https://developers.weixin.qq.com/s/wLxQuwm1786m
instance对象支持的方法:
常用的就是获取组件(类似于获取dom节点),和设置样式和class,调用app service方法 除了以上方法,还有强大的触发器函数的使用,可监听appservice 层中的data变化,具体demo请查看官方文档 官方文档经过实机测试,不出出现卡顿效果
注意事项
官方bug:
个人总结bug:
1.wxs不能使用ES6+语法,否则会报错(勾选了ES6转ES5也没用)2.
console.log()
不能直接打印对象,需要JSON.stringify
3.当然不能调用
app service
环境中的方法和wx.xxxx方法
赞赏