小程序項目中遇到左滑刪除的交互需求缠劝,體驗(yàn)了幾個流行的小程序,各廠的解決方案有不同骗灶,也有類似惨恭。為一探究竟,自己動手實(shí)現(xiàn)了京東購物耙旦,印象筆記隨時記的左滑交互脱羡。在文章的最后,給出了自己的方案免都,總結(jié)了文章中三種方案的優(yōu)缺點(diǎn)锉罐。
方案一:使用scroll-view,代表:印象筆記隨時記
原理
用scroll-view實(shí)現(xiàn)左滑刪除交互的原理非常簡單绕娘,設(shè)置一個支持橫向滑動的scroll-view脓规,同時將子組件的寬度設(shè)置為scroll-view的寬度加上刪除按鈕的寬度。由于子組件的寬度大于scroll-view的寬度险领,自然地侨舆,就可以進(jìn)行橫向滑動了。
代碼
<scroll-view class="scroll-view-scroller" scroll-x>
<view class='scroll-view-item'>
<view class="scroll-view-delete">
<text>刪除</text>
</view>
</view>
</scroll-view>
.scroll-view-scroller {
width: 375px; //處于demo考慮 ,scroll-view寬度設(shè)為固定值舷暮,實(shí)際項目中請自行計算
}
.scroll-view-item {
width: 475px; // 300(scroller的寬度) + 100(delete按鈕的寬度)
height: 100px;
background: blue;
position: relative;
}
.scroll-view-delete {
width: 100px; //按鈕的寬度
position: absolute;
right: 0;
top: 0;
bottom: 0;
background: red;
color: #fff;
text-align: center;
line-height: 100px;
}
優(yōu)點(diǎn)
- 實(shí)現(xiàn)成本低
- 兼容所有小程序版本
- 組件高度可設(shè)為自適應(yīng)
缺點(diǎn)
- 當(dāng)用戶手指離開屏幕時态罪,刪除按鈕不能自動隱藏或顯示
- 有一個明顯的橫向滾動條
- 和原生的左滑體驗(yàn)差別較大
方案二: 檢測左滑手勢,代表:京東購物下面,每日優(yōu)鮮
原理
通過touch事件复颈,計算用戶手指左向滑動的距離,當(dāng)用戶手指離開屏幕時沥割,如果左向滑動的距離大于預(yù)設(shè)閥值耗啦,比如50像素,就打開左滑動畫机杜。
當(dāng)我在體驗(yàn)京東購物和每日優(yōu)鮮小程序上的左滑交互時帜讲,發(fā)現(xiàn)兩者都存在一些細(xì)節(jié)上的缺失。比如沒有將左滑限制為橫掃椒拗,沒有檢測多點(diǎn)觸控似将。這兩點(diǎn)應(yīng)該還是出于簡化代碼的考慮得吧。
代碼
<view class="swipe-delete-wrapper"
bind:touchstart="onTouchStart"
bind:touchmove="onTouchMove"
bind:touchcancel="onTouchEnd"
bind:touchend="onTouchEnd"
>
<view class="swipe-delete-content {{swiped ? 'open' : ''}}" bindtap='closeSwipe'>
</view>
<view class="swipe-delte-btn">
<text>刪除</text>
</view>
</view>
.swipe-delete-wrapper {
height: 100px;
width: 100%;
position: relative;
}
.swipe-delte-btn {
position: absolute;
right: 0;
width: 100px;
top: 0;
text-align: center;
background: red;
bottom: 0;
line-height: 100px;
color: #fff;
}
.swipe-delete-content {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: blue;
z-index: 2;
transition: transform 200ms linear;
}
.swipe-delete-content.open {
transform: translateX(-100px);
}
onTouchStart(event) {
if (event.touches[0]) {
this.touchStartPosition = event.touches[0].clientX;
}
}
onTouchMove(event) {
if (event.touches[0]) {
this.touchEndPosition = event.touches[0].clientX;
}
}
closeSwipe() {
this.setData({
swiped: false
})
}
onTouchEnd() {
if (this.touchStartPosition && this.touchEndPosition) {
let delta = this.touchStartPosition - this.touchEndPosition;
//左滑距離大于閥值蚀苛,顯示刪除按鈕
if(delta > 50) {
this.setData({
swiped: true
})
}
//右滑距離小于閥值在验,隱藏刪除按鈕
if(delta < -50) {
this.setData({
swiped: false
})
}
}
this.touchStartPosition = null;
this.touchEndPosition = null;
}
優(yōu)點(diǎn)
- 兼容所有小程序版本
- 體驗(yàn)好于scroll-view
- 組件高度可設(shè)為自適應(yīng)
缺點(diǎn)
- 滑動不跟手
- 和原生的左滑體驗(yàn)差別較大
方案三:使用movable-view
原理
從1.2.0開始,小程序提供了movable-view堵未,配合movable-area腋舌,可以實(shí)現(xiàn)非常流暢的滑動效果。
首先渗蟹,我們需要確定組件的寬度和刪除按鈕的寬度块饺,組件的寬度就是movable-view的寬度赞辩,而movable-area的寬度就是組件的寬度減去刪除按鈕的寬度。這樣授艰,我們就可以在限定的范圍內(nèi)滑動了辨嗽,當(dāng)超過最大滑動距離時,movable-view還會自動提供一個非常流暢的過界動畫和回彈效果想诅,媲美原生召庞。
代碼
<view class="moveable-item"
bind:touchstart="onTouchStart"
bind:touchmove="onTouchMove"
bind:touchend="onTouchEnd"
bind:touchcancel="onTouchEnd">
<movable-area class="movable-wrapper">
<movable-view class='movable-item' out-of-bounds="true" direction="horizontal" x="{{x}}"></movable-view>
</movable-area>
<view class="move-able-delete-section">
<text>刪除</text>
</view>
</view>
.moveable-item {
display: flex;
flex-direction: row;
position: relative;
align-items: center;
background: red;
}
.movable-wrapper {
min-height: 100px;
background: #ddd;
flex: 1;
position: relative;
}
.movable-item {
position: relative;
height: 100px;
width: 375px;
background: blue;
flex:1
}
.move-able-delete-section {
width: 100px;
height: 100%;
text-align: center;
color: #fff;
}
onTouchStart(event) {
if(event.touches[0]){
this.touchStartPosition = event.touches[0].clientX;
}
}
onTouchMove(event) {
if (event.touches[0]) {
this.touchEndPosition = event.touches[0].clientX;
}
}
onTouchEnd(event) {
if (this.touchStartPosition && this.touchEndPosition) {
console.log(this.touchStartPosition - this.touchEndPosition)
let delta = this.touchStartPosition - this.touchEndPosition;
//left
if(delta > 0) {
if(delta> 40) {
this.setData({
x: -100
})
}else {
this.setData({
x: 0
})
}
}else {
//right
if (Math.abs(delta) > 40) {
this.setData({
x: 0
})
}else {
this.setData({
x: -100
})
}
}
this.touchStartPosition = null;
this.touchEndPosition = null;
}
}
優(yōu)點(diǎn)
- 動畫流暢,操作跟手
- 媲美原生左滑交互
缺點(diǎn)
- 組件需要固定高度
總結(jié)
方案一作為小程序早期的解決方案来破,目前不再推薦。
方案二由于無需限制組件的高度忘古,具有很大的普適性徘禁。如果你的小程序中組件高度需要自適應(yīng),那么推薦你使用方案二髓堪。
如果你的小程序中組件的高度是固定的送朱,那么方案三無疑是最優(yōu)的方案,你可以提供給用戶媲美原生的左滑體驗(yàn)干旁。