在小程序中實(shí)現(xiàn)左滑刪除(側(cè)滑刪除)并不是一個(gè)很輕松的事情,因?yàn)橛袔讉€(gè)問(wèn)題(坑)是需要我們考慮的:
- 小程序的事件系統(tǒng)是存在缺陷的,其中不能在事件處理過(guò)程中調(diào)用
preventDefault來(lái)動(dòng)態(tài)決定事件是否允許冒泡,假設(shè)用戶斜著滑動(dòng)一個(gè)條目時(shí),我們可能需要根據(jù)用戶滑動(dòng)的斜率等等來(lái)判斷這次滑動(dòng)是用來(lái)觸發(fā)側(cè)滑還是頁(yè)面滾動(dòng),在這方面的處理可能比較復(fù)雜。
這里感謝有專自媒體的踩坑文章: 微信小程序?qū)崿F(xiàn)左滑刪除-一切沒有那么簡(jiǎn)單
- 一般的,我們可能比較習(xí)慣這么去寫左滑刪除
html
<view wx:for='{{list}}' style="left:-{{item.offset}}rpx" class="scroll-view-item">
</view>
js
`touchMove`(e) {
if (e.touches.length == 1) {
let pointBefore = this.data.pointBefore;
let thisPoint = e.touches[0];
let slope = Math.abs(pointBefore.clientY - thisPoint.clientY) / Math.abs(pointBefore.clientX - thisPoint.clientX);
console.log(slope)
if (slope > 0.57) {
return
}
let index = e.currentTarget.dataset.index;
let offsetResult = 0;
//手指移動(dòng)時(shí)水平方向位置
let moveX = e.touches[0].clientX;
//手指起始點(diǎn)位置與移動(dòng)期間的差值
let disX = this.data.startX - moveX;
let resultX = this.data.startOffset + disX;
if (resultX <= 0) {//如果移動(dòng)距離小于等于0,說(shuō)明向右滑動(dòng),文本層位置不變
offsetResult = resultX;
} else if (resultX >= this.data.maxOffset) {
//控制手指移動(dòng)距離最大值為刪除按鈕的寬度
offsetResult = this.data.maxOffset;
} else if (resultX > 0) {//移動(dòng)距離大于0,文本層left值等于手指移動(dòng)距離
offsetResult = resultX;
}
//更新列表的狀態(tài)
this.setData({
offset: offsetResult
});
}
}
但是在真機(jī)測(cè)試的時(shí)候總是卡卡的,一種可能是:
小程序不推薦在js里頭監(jiān)聽touchMove等ui事件并且每次都去修改ui內(nèi)容,原因:
WXS相應(yīng)事件
背景
有頻繁用戶交互的效果在小程序上表現(xiàn)是比較卡頓的,例如頁(yè)面有 2 個(gè)元素 A 和 B,用戶在 A 上做
touchmove手勢(shì),要求 B 也跟隨移動(dòng),<movable-view> 就是一個(gè)典型的例子。一次touchmove事件的響應(yīng)過(guò)程為:a、
touchmove事件從視圖層(Webview)拋到邏輯層(App Service)b、邏輯層(App Service)處理
touchmove事件,再通過(guò) setData 來(lái)改變 B 的位置一次
touchmove的響應(yīng)需要經(jīng)過(guò) 2 次的邏輯層和渲染層的通信以及一次渲染,通信的耗時(shí)比較大。此外 setData 渲染也會(huì)阻塞其它腳本執(zhí)行,導(dǎo)致了整個(gè)用戶交互的動(dòng)畫過(guò)程會(huì)有延遲。
另外,從CRP(標(biāo)準(zhǔn)渲染路徑)來(lái)說(shuō),我們這里頻繁地調(diào)用 setData來(lái)修改元素的 left 樣式,會(huì)導(dǎo)致網(wǎng)頁(yè)不斷地進(jìn)行 layout,style,composite操作,導(dǎo)致卡頓。而使用 transform 樣式僅影響composite操作,同樣可以做到元素的左移,這也是movable-view的做法。
使用movable-view的另一個(gè)好處
使用movable-view不需要我們手動(dòng)處理touchmove事件來(lái)修改左滑元素的位置,也因此避免了多次setData可能帶來(lái)的卡頓。
這里給出使用 movable-view 的代碼
js
Page({
data: {
x: wx.getSystemInfoSync().windowWidth / 750 * 200
},
})
wxml
<movable-area style="height: 300rpx; margin-bottom: 24rpx;width:{{showLike?'700rpx':'900rpx'}};position:relative;left: {{showLike?'25rpx':'-175rpx'}};" >
<movable-view
x="{{x}}"
class="scroll-view-item" style="width: 700rpx; height: 300rpx;"
direction="horizontal" out-of-bounds="true">
<view class="card-content" bind:tap="bindGroupTapInner">
<text class="group-title">側(cè)滑刪除</text>
</view>
<view class="button-edit button-slide" bindtap="bindGroupEditTap">
<i class="iconfont icon-editor"
style='font-size:58rpx; color:white; position:absolute; top:14rpx; left:16rpx;'/>
</view>
</movable-view>
</movable-area>
稍微要注意一點(diǎn)的是控制好movable-view和movable-area的寬度和位置,這里由于不同的需求要求不同,建議手動(dòng)畫圖計(jì)算。
另外,movable-view內(nèi)部幫我們解決了事件傳遞的問(wèn)題,能夠左滑的touchmove就不會(huì)傳遞給外層的元素,估計(jì)是使用了wxs函數(shù)吧,好像wxs中處理事件是可以控制事件冒泡的,但是筆者還未嘗試,同時(shí)官方文檔有些不足,可以看這里。