微信小程序-左滑顯示刪除按鈕

最終效果

實現思路

  1. 使用微信小程序的movable-view組件。movable-view
  2. 使用position: absolute;,將可滑動部分(z-index值較大)放置在刪除按鈕(z-index值較小)之上,最開始是遮住刪除按鈕的。
  3. 使用touchstarttouchend屬性綁定方法,控制刪除按鈕的顯示隱藏。

代碼

wxml

<view class="container">
  <movable-area>
    <movable-view direction="horizontal" out-of-bounds="{{true}}" friction="150" x="{{x}}" bindtouchstart="handleTouchStart" bindtouchend="handleTouchEnd" >
      <view class="card-container">
        <view>{{text}}</view>
        <view class="show-operations" catchtouchstart="toggle" catchtouchend="emptyFunc">...</view>
      </view>
    </movable-view>
  </movable-area>
  <view class="operations-content" >
    <view class="operation-button" catchtap="handleDelete">
      刪除
    </view>
  </view>
</view>
複製代碼

在使用movable-view中用到的屬性:javascript

  • direction="horizontal",設置movable-view爲橫向移動。
  • out-of-bounds="{{true}}",設置超過區域以後,movable-view是否還能夠移動,這個屬性默認值爲false,若是不添加這個屬性,就不會有回彈效果。
  • friction="150"設置摩擦係數,摩擦係數越大,滑動越快中止。
  • x="{{x}}"設置x軸方向的偏移。

tip: movable-view 必須設置width和height屬性,不設置默認爲10px。
tip: movable-view 默認爲絕對定位,top和left屬性爲0pxcss

更多內容參考:movable-viewhtml

wxss

由於movable-view 默認爲絕對定位,因此設置刪除按鈕部分的z-index值比movable-viewz-index小,就能將刪除按鈕遮住。java

/* 可移動部分樣式 */
movable-area {
  width: 510rpx; 
}
.container,
movable-view {
  box-sizing: border-box;
  width: 750rpx;
  height: 200rpx;
}
.container {
  position: relative;
  display: flex;
  flex-direction: row;
}
movable-view {
  z-index: 5; 
  padding: 10rpx;
  overflow: hidden;
  background-color: green;
}

/* 隱藏部分樣式 */
.operations-content {
  position: absolute;
  display: flex;
  flex-direction: row-reverse;
  justify-content: left;
  align-items: center;
  z-index: 2; 
  right: 0;
  width: 280rpx; /* 隱藏部分的寬度 */
  height: 200rpx;
  background-color: yellow;
}
.operation-button {
  width: 150rpx;
  height: 150rpx;
  line-height: 150rpx;
  text-align: center;
  border-radius: 50%;
  margin: 0 20rpx;
  background-color: gray;
  color: #fff;
}

/* 卡片樣式 */
.card-container {
  width: 100%;
  height: 180rpx;
  border-radius: 5rpx;
  font-size: 20px;
  word-break: break-all;
  background-color: rgba(255, 255, 255, 0.7);
}
.show-operations {
  position: absolute;
  bottom: 10rpx;
  right: 10rpx;
  width: 80rpx;
  height: 80rpx;
  border-radius: 50%;
  text-align: center;
  line-height: 80rpx;
}
複製代碼

js

經過控制movable-viewx屬性來控制刪除按鈕的顯示和隱藏。json

綁定movable-viewtouchstarttouchend事件,記錄下觸摸開始時的x軸座標start_x和觸摸結束時的x軸座標current_x,若是current_x - start_x小於0就說明是朝左滑的,設置movable-viewx-140來顯示刪除按鈕,不然就是向右滑的,經過設置x值爲0來隱藏刪除按鈕。小程序

Component({
  properties: {
    text: {
      type: String,
      value: '示例內容示例內容'
    },
    index: Number
  },
  data: {
    x: 0,  // 注意,這裏經過x屬性設置的寬度的單位是px
    start_x: 0,
    operations_visible: false
  },
  methods: {
    handleTouchStart: function (event) {
      this.setData({
        start_x: event.touches[0].clientX // 觸摸開始時的橫座標
      })
    },
    handleTouchEnd: function (event) {
      const current_x = event.changedTouches[0].clientX; // 觸摸結束時的橫座標
      const { start_x } = this.data;
      const direction = current_x - start_x; // 判斷滑動的方向

      if (direction < 0) {
        this.showOperations();
      } else {
        this.hideOperations();
      }
    },
    toggle: function () {
      let operations_visible = this.data.operations_visible;

      if (operations_visible) {
        this.hideOperations();
      } else {
        this.showOperations();
      }
    },
    handleDelete () {
      const index = this.properties.index;
      this.hideOperations();
      this.triggerEvent('delete', { index });
    },
    showOperations: function () {
      this.setData({
        x: -140,
        operations_visible: true
      });  
    },
    hideOperations: function () {
      this.setData({
        x: 0,
        operations_visible: false
      });
    },
    emptyFunc: function () {
      return false;
    }
  }
})
複製代碼

在顯示隱藏的部分能夠作一個優化,在顯示狀態下左滑和在隱藏狀態下右滑,不用設置x的值。微信小程序

handleTouchEnd: function (event) {
      const operations_visible = this.data.operations_visible;
      const current_x = event.changedTouches[0].clientX; // 觸摸結束時的橫座標
      const { start_x } = this.data;
      const direction = current_x - start_x; // 判斷滑動的方向

      if (direction < 0) {
        !operations_visible && this.showOperations();
      } else {
        operations_visible && this.hideOperations();
      }
    },
複製代碼

json

{
  "component": true
}
複製代碼

解決的問題

  1. 由於有回彈的效果,因此在滑動的過程當中會出現一個空隙。經過設置movable-area的寬度可以解決這個問題。
movable-area {
  width: 510rpx; 
}
複製代碼

這裏將movable-area的寬度設置爲510rpx,而不是(750-280=470)470rpx,就能讓回彈的範圍在黃色部分,「隱藏」這個空隙。數組

必須設置movable-area的寬度,不然默認寬高爲10px,movable-view可滑動的範圍會更大,在滑動的過程當中會出現中間空隙很大的狀況。bash

  1. 在父元素movable-view中添加了bindtouchstartbindtouchend屬性用於綁定觸摸開始事件和觸摸結束事件。在子元素中有三個點,點擊三個點的時候可以切換刪除按鈕的顯示和隱藏。可是使用bindtap屬性綁定元素的點擊事件,父元素上綁定的觸摸事件也會被觸發。因此須要使用catch綁定事件來阻止事件冒泡。
<view class="show-operations" catchtouchstart="toggle" catchtouchend="emptyFunc">...</view>
複製代碼
emptyFunc: function () {
  return false;
}
複製代碼
  1. 實際項目使用了本文的思路,根據提出的bug作出了一些調整。

(1)滑動速度比較慢。微信

解決方法:調整屬性,使滑動的效果變快。

<movable-view direction="horizontal" out-of-bounds="{{true}}" damping="100" friction="100" x="{{x}}"
      bind:touchstart="handleTouchStart" bind:touchend="handleTouchEnd">
複製代碼

(2)當上下滑動的過程當中,會誤觸發左右滑動。

解決方法:獲取滑動起始和結束時的clientY,當二者差值的絕對值大於某個範圍的時候,就認爲是純上下滑動,不觸發左右滑動。

(3)當點擊卡片時,會誤觸發左右滑動。

解決方法:使用1而不是0來判斷左右滑

handleTouchStart: function (event) {
      this.hideAllOperations();
      const { clientX, clientY } = event.touches[0];
      this.setData({
        start_x: clientX,
        start_y: clientY
      });
    },
    handleTouchEnd: function (event) {
      const { clientX, clientY } = event.changedTouches[0];
      const { start_x, start_y } = this.data;

      if (Math.abs(clientY - start_y) > 50)  return; // 處理上下滑動誤觸左右滑動的狀況
      const direction = clientX - start_x;

      // 這裏使用1來判斷方向,保證用戶在非滑動時不觸發滾動(有時點擊也會產生些許x軸座標的變化)
      if (direction < -1) {
        this.showOperations();
      } else if (direction > 1) {
        this.hideOperations();
      } else {
        this.toBrandDetail();
      }
    },
複製代碼

(4)在列表中只能有一個隱藏的按鈕是顯示出來的,可是當前的方式沒有對滑動卡片的數量作限制。

解決方法:在父組件中定義一個數組(數組元素爲滑動卡片的x值),用於控制全部卡片的顯示隱藏。當滑動開始時將數組中的全部值設置爲0,當左滑顯示卡片的時候,將滑動顯示出按鈕的那個卡片對應的數組中的x值設置爲-85

更多微信小程序事件相關,參考:微信小程序事件

使用列表

若是要以列表的形式使用,就在父組件中引入該組件,並經過數組來控制列表。

父組件的wxml:

<view>
  <block wx:for="{{test_list}}" wx:key="{{index}}">
    <movable-component text="{{item}}" index="{{index}}" class="list-item" catch:delete="deleteItem"/>
  </block>
</view>
複製代碼

父組件的js:

Page({ 
  data: {
    test_list: null
  },
  onLoad: function () {
    let list_arr = [];
    for (let i = 0; i < 5; i++) {
      list_arr.push(`${Array(10).fill(i + 1).join(' ')}`);
    }
    this.setData({
      test_list: list_arr
    })
  },
  deleteItem: function (event) {
    // 一些其他操做,好比發起刪除請求
    const index = event.detail.index;
    let arr = this.data.test_list;
    arr.splice(index, 1);
    this.setData({
      test_list: arr
    })
  }
})
複製代碼

父組件的wxss:

.list-item {
  display: block;
  margin: 20rpx 0;
}
複製代碼

父組件的json:

{
  "usingComponents": {
    "movable-component": "./components/movableView/movableView"
  }
}
複製代碼

PS: 如發現文中可優化或不當之處,請不吝賜教(。・`ω´・)。

相關文章
相關標籤/搜索