需求:实现左滑删除功能

一、代码组成
- SwipeCell.vue : 可左右滑动做删除等其他操作的组件
- SwipeCell.less : 组件的样式表
- combination.js
- GoodsType.vue : 使用滑动组件的页面文件
1、SwipeCell.vue
<template>
<!-- 可左右滑动做删除等其他操作的组件 -->
<view
class="swipe-cell"
>
<view
:style="{
'transition-duration': `${duration}s`,
'transform': `translate3d(${movedDistance}rpx, 0rpx, 0rpx)`
}"
@touchstart="onTouchStart"
@touchmove="onTouchMove"
@touchend="onTouchEnd"
>
<view
v-if="leftWidth"
class="swipe-cell__left"
@tap="slotClick('left')"
>
<slot name="left" />
</view>
<slot class="cell" />
<view
v-if="rightWidth"
class="swipe-cell__right"
@tap="slotClick('right')"
>
<slot name="right" />
</view>
</view>
</view>
</template>
<script>
import './SwipeCell.less';
import { getDirection, resetTouchStatus } from '@/combination';
export default {
name: 'SwipeCell',
props: {
duration: {
type: Number,
default: 0.4
},
// 右边slot 的宽度 rpx为单位
rightWidth: {
type: Number,
default: 0
},
// 左边slot 的宽度 rpx为单位
leftWidth: {
type: Number,
default: 0
},
// prop传进来的滑动距离
propMovedDistance: {
type: Number,
default: 0
}
},
data () {
return {
movedDistance: 0, // 元素应该滑动的距离
activeIndex: 0, // 当前查看的tab的索引
newTabList: [],
xPositon: 0, // 容器在X轴移动的距离
swipeable: true,
swiping: false,
direction: '',
deltaX: 0,
deltaY: 0,
offsetX: 0,
offsetY: 0,
startX: 0,
startY: 0,
minSwipeDistance: 50
};
},
watch: {
propMovedDistance (val) {
this.movedDistance = val;
}
},
methods: {
touchStart (event) {
resetTouchStatus(this);
var touch = event.touches[0];
this.startX = touch.clientX;
this.startY = touch.clientY;
},
touchMove (event) {
var touch = event.touches[0];
this.deltaX = touch.clientX - this.startX;
this.deltaY = touch.clientY - this.startY;
this.offsetX = Math.abs(this.deltaX);
this.offsetY = Math.abs(this.deltaY);
this.direction = this.direction || getDirection(this.offsetX, this.offsetY);
},
onTouchStart (event) {
if (!this.swipeable) { return; }
this.swiping = true;
this.touchStart(event);
},
onTouchMove (event) {
if (!this.swipeable || !this.swiping) { return; }
this.touchMove(event);
},
// watch swipe touch end
onTouchEnd () {
if (!this.swipeable || !this.swiping) { return; }
if (!this.leftWidth && this.deltaX > 0 && !this.movedDistance) return;
if (!this.rightWidth && this.deltaX < 0 && !this.movedDistance) return;
if (this.direction === 'horizontal' && this.offsetX >= this.minSwipeDistance) {
this.movedDistance = this.deltaX > 0 ? this.leftWidth : -this.rightWidth;
}
this.swiping = false;
this.$emit('swipeEnd', this.movedDistance);
},
slotClick (type) {
this.movedDistance = 0;
resetTouchStatus(this);
this.$emit('close', type);
},
getMovedDistance () {
return this.movedDistance;
}
}
};
</script>
2、SwipeCell.less
.swipe-cell {
overflow: hidden;
position: relative;
&__left {
position: absolute;
top: 0;
height: 100%;
left: 0;
transform: translate3d(-100%, 0, 0);
}
.cell {
}
&__right {
position: absolute;
top: 0;
height: 100%;
right: 0;
transform: translate3d(100%, 0, 0);
}
}
3、combination.js
/**
* 获取滑动的方向,垂直、水平
* @param {*} x
* @param {*} y
* @returns horizontal: 水平; vertical: 垂直
*/
export function getDirection (x, y) {
var MIN_DISTANCE = 10;
if (x > y && x > MIN_DISTANCE) {
return 'horizontal';
}
if (y > x && y > MIN_DISTANCE) {
return 'vertical';
}
return '';
}
export function resetTouchStatus (that) {
that.direction = '';
that.deltaX = 0;
that.deltaY = 0;
that.offsetX = 0;
that.offsetY = 0;
}
4、GoodsType.vue
<template>
<SwipeCell
v-for="(item, ind) in records"
:key="item.id"
:right-width="122"
:async-close="true"
:propMovedDistance="ind === swipedIndex ? propMovedDistance : 0"
@close="onClose"
@swipeEnd="(distance) => swipeEndHandle(ind, distance)"
>
<view class="flex f-ai-c f-jc-sb goods-type">
<view
class="flex f-d-c goods-type-i flex1"
@tap="toAddType(item.id)"
>
<text class="fz-30">
{{ item.typeName }}
</text>
<text
class="fz-28"
style="color: #999999;"
>
商品数量{{ item.goodsCount || 0 }}
</text>
</view>
</view>
<template #right>
<view
class="del-btn flex f-ai-c f-jc-c fz-27 c-f"
:style="{borderRadius: !ind ? '0 14rpx 0 0' : ind === records.length - 1 ? '0 0 14rpx 0' : '0'}"
@tap="delItem(item)"
>
删除
</view>
</template>
</SwipeCell>
</template>
<script>
export default {
name: 'GoodsType',
components: { SwipeCell },
data () {
return {
records: [],
swipedIndex: 0, // 当前左滑删除的元素的index
propMovedDistance: 0 // 当前左滑删除的元素 移动的距离
};
},
methods: {
swipeEndHandle (ind, distance) {
this.swipedIndex = ind;
this.propMovedDistance = distance;
},
onClose (type) {
switch (type) {
case 'left':
case 'right':
Taro.showModal({
title: '提示',
content: '是否要删除',
success: (res) => {
if (res.confirm) {
typeDelete(this.delingid, true).then(res => {
if (res) {
Taro.showToast({
title: '操作成功',
icon: 'success',
duration: 1000
});
const index = this.records.findIndex(r => r.id === this.delingid);
this.records.splice(index, 1);
}
});
}
}
});
break;
}
}
}
}
</script>
网友评论