Taro 实现 微信小程序滑动删除功能

需求:实现左滑删除功能

image.png

一、代码组成

  • 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>
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值