從京東購物,印象筆記看小程序左滑交互的實(shí)現(xiàn)

小程序項(xiàng)目中遇到左滑刪除的交互需求,體驗(yàn)了幾個(gè)流行的小程序,各廠的解決方案有不同,也有類似。為一探究竟,自己動(dòng)手實(shí)現(xiàn)了京東購物,印象筆記隨時(shí)記的左滑交互。在文章的最后,給出了自己的方案,總結(jié)了文章中三種方案的優(yōu)缺點(diǎn)。

方案一:使用scroll-view,代表:印象筆記隨時(shí)記

原理

用scroll-view實(shí)現(xiàn)左滑刪除交互的原理非常簡單,設(shè)置一個(gè)支持橫向滑動(dòng)的scroll-view,同時(shí)將子組件的寬度設(shè)置為scroll-view的寬度加上刪除按鈕的寬度。由于子組件的寬度大于scroll-view的寬度,自然地,就可以進(jìn)行橫向滑動(dòng)了。


scroll_delete.gif

代碼

<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í)際項(xiàng)目中請自行計(jì)算
}
.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)用戶手指離開屏幕時(shí),刪除按鈕不能自動(dòng)隱藏或顯示
  • 有一個(gè)明顯的橫向滾動(dòng)條
  • 和原生的左滑體驗(yàn)差別較大

方案二: 檢測左滑手勢,代表:京東購物,每日優(yōu)鮮

原理

通過touch事件,計(jì)算用戶手指左向滑動(dòng)的距離,當(dāng)用戶手指離開屏幕時(shí),如果左向滑動(dòng)的距離大于預(yù)設(shè)閥值,比如50像素,就打開左滑動(dòng)畫。
當(dāng)我在體驗(yàn)京東購物和每日優(yōu)鮮小程序上的左滑交互時(shí),發(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)

  • 滑動(dòng)不跟手
  • 和原生的左滑體驗(yàn)差別較大

方案三:使用movable-view

原理

從1.2.0開始,小程序提供了movable-view,配合movable-area,可以實(shí)現(xiàn)非常流暢的滑動(dòng)效果。
首先,我們需要確定組件的寬度和刪除按鈕的寬度,組件的寬度就是movable-view的寬度,而movable-area的寬度就是組件的寬度減去刪除按鈕的寬度。這樣,我們就可以在限定的范圍內(nèi)滑動(dòng)了,當(dāng)超過最大滑動(dòng)距離時(shí),movable-view還會(huì)自動(dòng)提供一個(gè)非常流暢的過界動(dòng)畫和回彈效果,媲美原生。


流暢方案

代碼

<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)

  • 動(dòng)畫流暢,操作跟手
  • 媲美原生左滑交互

缺點(diǎn)

  • 組件需要固定高度

總結(jié)

方案一作為小程序早期的解決方案,目前不再推薦。
方案二由于無需限制組件的高度,具有很大的普適性。如果你的小程序中組件高度需要自適應(yīng),那么推薦你使用方案二。
如果你的小程序中組件的高度是固定的,那么方案三無疑是最優(yōu)的方案,你可以提供給用戶媲美原生的左滑體驗(yàn)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容