基于uniapp实现侧滑删除效果

728 阅读1分钟

如何实现小程序端的侧滑删除操作

效果演示

show.gif

实现思路

前端实现滑动效果,根本上还是利用element的样式变化,通过监听touch事件,从而达到侧滑的效果。 先看实现思路:
(为方便说明,左边展示的内容盒子称为盒子A,隐藏的删除盒子称为盒子B)

思路1. 利用元素translateX()做平移

show1.png 通过监听touchMove, 当移动距离达到我们展示的距离,改变element的translateX(-盒子B的宽度), 通过重新设置transform,利用transition: transform time timeFun达到平滑过渡效果;

思路2. 通过定位改变元素left值

show2.png 同样是通过监听touchMove, 当移动距离达到我们展示的距离,改变盒子A的left定位, 通过重新设置left,利用transition: left time timeFun达到平滑过渡效果;

思路比较

从实现上可以看出,思路1需要将移动效果同时追加到两个element上,增加了内核的渲染成本,而思路2,只需要移动一个脱离了标准文档流的定位元素,渲染成本要小于思路1。
从组件封装来看,选择UI交互和事件处理单独隔离,UI交互负责滑动效果,事件处理部分交给业务侧单独维护

代码展示

简单的业务场景实现代码如下:

<template>
  <view
    class="slider-module"
    :style="{'height': heightStyle}"
    @touchstart.prevent="touchstart"
    @touchmove.prevent="touchmove($event)"
  >
    <!-- 侧滑左侧内容展示 -->
    <div
      :class="['slider-left', { 'show-del': showDel }]"
      :style="{'left': showDel ? sliderWidth : 0}"
    >
      <slot name="slider-left" />
    </div>
    <!-- 侧滑右侧隐藏区域模块 -->
    <div class="slider-right">
      <slot name="slider-right" />
    </div>
  </view>
</template>

<script>
export default {
  props: {
    heightStyle: {
      type: String,
      default: '112rpx;'
    },
    sliderWidth: {
      type: String,
      default: '-144rpx'
    }
  },
  data() {
    return {
      startPot: {
        pageX: 0,
        pageY: 0
      }, // 滑动pageX节点坐标信息
      showDel: false // 展示删除按钮
    };
  },
  methods: {
    /** 触摸事件处理 */
    touchstart(e) {
      this.startPot = {
        pageX: e.changedTouches[0].pageX,
        pageY: e.changedTouches[0].pageY
      };
    },
    /**通过计算pageY的偏移量来避免上下滑动距离限制触发左滑条件 */
    touchmove(e) {
      if (
        e.changedTouches[0].pageX - this.startPot.pageX <= -30 &&
        Math.abs(e.changedTouches[0].pageY - this.startPot.pageY) < 10
      ) {
        if (!this.showDel) this.showDel = true; // 避免重复赋值
      } else if (
        e.changedTouches[0].pageX - this.startPot.pageX > 30 &&
        Math.abs(e.changedTouches[0].pageY - this.startPot.pageY) < 10
      ) {
        if (this.showDel) this.showDel = false;
      }
    }
  }
};
</script>

<style lang="scss" scoped>
.slider-module {
  width: 100%;
  background-color: $xe-bg-color;
  position: relative;
  .slider-left {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 2;
    width: 100vw;
    box-sizing: border-box;
    transition: left 0.2s ease-in;
  }
  .slider-right {
    position: absolute;
    top: 0;
    right: 0;
    z-index: 1;
    box-sizing: border-box;
    background-color: $xe-color-text-del;
  }
}
</style>