如何实现小程序端的侧滑删除操作
效果演示
实现思路
前端实现滑动效果,根本上还是利用element的样式变化,通过监听touch事件,从而达到侧滑的效果。
先看实现思路:
(为方便说明,左边展示的内容盒子称为盒子A,隐藏的删除盒子称为盒子B)
思路1. 利用元素translateX()做平移
通过监听touchMove, 当移动距离达到我们展示的距离,改变element的translateX(-盒子B的宽度), 通过重新设置transform,利用transition: transform time timeFun达到平滑过渡效果;
思路2. 通过定位改变元素left值
同样是通过监听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>