使用wxs优化拖动效果实战总结
下面是一个真实的项目场景:需要选中一张图中的某个图案或文本,对其进行放大缩小并将它移动个位置。
拖动前 选中状态 拖动后
最终效果
做这个事,有几个JS事件可以帮到我们
- touchstart: 拖动前的点击选中事件,这个事件可能需要和tap事件和进行下区别 ,经实际测试如果在一个view中同时捕获tap和touchstart事件,如:<view catchtap='tap' catchtouchstart='touchatart'> </view>,则只会触发touchart事件
- touchmove: 选中后鼠标不松开会触发此事件
- touchend:选中移动并松开后会触发此事件
在处理过程中,比如在拖动过程中会产生大量touchmove事件导致页面不断渲染,会有明显的卡顿现象出现,
所以这里我们需要用到WMS这个技术来处理移动事件。
个人感觉用WXS的时候注意以下几点:
1. 不要让WXS过多参与业务,发挥它的优势,只要它解决渲染性能问题
2. 如何向WMS传送参数
3. 如何让WMS和JS 进行交互
下面是解决拖动效果的WMS代码,文件名为move.wxs
var startX = 0 var startY = 0 var lastLeft = lastTop = 0 var flag var target_id ,target_top,target_left,target_width,target_height; var canvas_width = 200, canvas_height = 350 ; var hRatioH ; var stop = false function touchstart(event, ins) { // stop = false; var touch = event.touches[0] || event.changedTouches[0] startX = touch.pageX startY = touch.pageY var flag = false ; if( event.target.dataset.targetid != target_id){ flag = true; } target_id = event.target.dataset.targetid; target_top = event.target.dataset.targettop; target_left = event.target.dataset.targetleft; target_width = event.target.dataset.targetwidth ; target_height = event.target.dataset.targetheight; hRatioH = event.target.dataset.hratioh ; canvas_width = event.target.dataset.canvasw; canvas_height = event.target.dataset.canvash; if(flag){ lastLeft = target_left lastTop = target_top } } function touchmove(event, ins) { var touch = event.touches[0] || event.changedTouches[0] var pageX = touch.pageX var pageY = touch.pageY var left = pageX - startX + lastLeft var top = pageY - startY + lastTop startX = pageX startY = pageY lastLeft = left lastTop = top if(target_id ){ ins.selectComponent('.selectBox').setStyle({ left: left + 'px', top: top + 'px' }) ins.selectComponent('#'+ target_id).setStyle({ //使用选择器获取组件的引用 left: left + 'px', top: top + 'px' }) } } module.exports = { touchstart: touchstart, touchmove: touchmove }
使用时,在WXML文件中进行声明和引用,如:<wxs module="move" src="./move.wxs"></wxs>
然后在需要进行拖动控制的组件上绑定WXS事件,并可以通过 data-xxx 机制向wxs 脚本传入page中的data中的数据,如 data-targetid="{{selectbox.targetid}}" ,这样脚本内部可以通过
<view class="selectBox" catchtouchstart="{{move.touchstart}}" catchtouchmove="{{move.touchmove}}" catch:touchend="{{move.touchend}}" data-targetid="{{selectbox.targetid}}" data-targettop="{{selectbox.top}}" data-targetleft="{{selectbox.left}}" data-targetwidth="{{selectbox.width}}" data-targetheight="{{selectbox.height}}" data-hRatioH="{{hRatioH}}" data-canvasW="{{windowWidth}}" data-canvasH="{{windowHeight}}">
另外wxs脚本可通过callMethod方式调js脚本可以向JS传递数据,但是callMethod机制无法获取JS的返回值
在使用WXS时,还需要注意一点,如果在 wxs 中对组件进行样式设置后,它的优先级比JS中要高,就是说如果wxs 和 js 中同样对某个样式操作,可能JS中的操作会无效。要解决这个问题,我们可利用wxs 提供的数据监听机制,当page中的data里某个数据发生变化后,会触发wxs中的事件,这样就可以利用WXS去设置和改变样式
(1) wxml中设置事件:如 <view change:prop="{{move.listenupdate}}" prop="{{box_left_top}}"></view>
move.listenupdate是wxs中的响应事件的函数,box_left_top 是page中data的数据名称
(2) wxs 中添加监听事件的响应函数
listenupdate: function(newValue, oldValue, ownerInstance, ins) { if(newValue){ console.log(newValue) var arr = newValue.split(":") var l = arr[0] ; var t = arr[1] ; ownerInstance.selectComponent('.selectBox').setStyle( { left: l + 'px', top: t + 'px' } ) } console.log('----------------prop observer------------------') }
(3)在js中更新data数据
this.setData({ box_left_top: (left*this.data.hRatioH-2) + ":" + (top*this.data.hRatioH-2) })