左滑删除这个效果在移动端十分常见,以购物车为例,具体实现源码如下:
1、 效果图

2、 wxml文件
<view class="container">
<scroll-view scroll-y class='warpper'>
<view class="cart-box {{item.isTouchMove?'touch-move-active':''}}" bindtouchstart="touchStart"
bindtouchmove="touchMove" data-index="{{index}}" wx:for="{{list}}" wx:key="id">
<view class="cart-wrapper">
<view class="radio-btn">
<radio bindtap="radioChange" data-id="{{item.id}}" checked="{{item.active}}"></radio>
</view>
<view class="img">
<image src="{{item.src}}"></image>
</view>
<view class="content">
<view class="goods-name">{{item.name}}</view>
<view class="goods-price">
<text class="new-price">{{'¥'+item.price}}</text>
</view>
</view>
<view class="num">
<text bindtap="changeNum" data-type="subtract" data-id="{{item.id}}">-</text>
<input bindchange="inputChange" bindblur="inputBlur" data-id="{{item.id}}" type="text" value="{{item.num}}" />
<text bindtap="changeNum" data-type="add" data-id="{{item.id}}">+</text>
</view>
</view>
<view class="remove" data-id="{{item.id}}" bindtap="delItem">删除</view>
</view>
</scroll-view>
<view class="footer-box">
<view class="left-btn">
<label>
<radio bindtap="allSelect" checked="{{checkedAll}}">全选</radio>
</label>
</view>
<view class="right-content">
<view class="sum-price" wx:if="{{sumPrice!==0}}">共计:<text>{{sumPrice}} </text>元 </view>
<view class="goPay">去结算</view>
</view>
</view>
</view>
3、 wxss文件
.container {
margin: 0;
padding: 0;
height: 100%;
position: relative;
box-sizing: border-box;
}
.warpper {
padding-bottom: 100rpx;
height: calc(100vh - 100rpx);
}
.cart-box{
display: flex;
margin: 10rpx 0;
height: 200rpx;
}
.cart-wrapper {
display: flex;
align-items: center;
width: 100%;
margin-left: -140rpx;
-webkit-transform: translateX(140rpx);
transform: translateX(140rpx);
-webkit-transition: all 0.4s;
transition: all 0.4s;
background-color: #eee;
}
.radio-btn {
display: flex;
align-items: center;
margin: 0 20rpx;
}
.cart-wrapper .img {
width: 120rpx;
height: 120rpx;
}
.cart-wrapper .img image {
width: 100%;
height: 100%;
}
.content {
display: flex;
padding-left: 30rpx;
width: 300rpx;
flex-direction: column;
justify-content: flex-start;
}
.content .goods-name {
color: #666;
font-size: 34rpx;
}
.content .goods-price {
margin-top: 30rpx;
font-size: 30rpx;
color: #3d3d3d;
}
.content .goods-price text {
margin-right: 30rpx;
}
.content .goods-price .new-price{
color: crimson;
}
.num{
align-self: flex-end;
display: flex;
align-items: center;
margin: 40rpx 10rpx;
width: 200rpx;
border: 1px solid #333;
border-radius: 10rpx;
background-color: #fff;
}
.num text{
display: flex;
justify-content: center;
align-items: center;
width: 80rpx;
height: 40rpx;
border: 0;
font-size: 48rpx;
}
.num input {
display: inline-block;
width: 100rpx;
height: 40rpx;
text-align: center;
font-size: 34rpx;
border-left: 1px solid #333;
border-right: 1px solid #333;
}
.remove{
width: 140rpx;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 36rpx;
color: #fff;
background-color: crimson;
transform: translateX(140rpx);
}
.touch-move-active .cart-wrapper,
.touch-move-active .remove {
-webkit-transform: translateX(0);
transform: translateX(0);
}
.footer-box {
display: flex;
align-items: center;
justify-content: space-between;
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 100rpx;
line-height: 100rpx;
background-color: #eee;
}
.left-btn {
padding: 0 40rpx;
}
.right-content{
display: flex;
}
.right-content .goPay{
margin-left: 30rpx;
}
.sum-price{
font-size: 38rpx;
color: #f00;
}
.goPay{
padding: 0 30rpx;
font-size: 34rpx;
color: #fff;
background-color: chocolate;
}
4、 js文件
Page({
data: {
list: [{
id: 1,
num: 1,
active: false,
isTouchMove: false,
name: '招财猫',
src: '/img/cat.jpg',
price: 29.99,
oldPrice: 89.99
}, {
id: 2,
num: 1,
active: false,
isTouchMove: false,
name: '哆啦A梦',
src: '/img/duola.jpg',
price: 59.98,
oldPrice: 99.98
}, {
id: 3,
num: 1,
active: false,
isTouchMove: false,
name: '狗',
src: '/img/dog.jpg',
price: 9.90,
oldPrice: 1299.99
}, {
id: 4,
num: 1,
active: false,
isTouchMove: false,
name: '招财猫4',
src: '/img/cat.jpg',
price: 129.99,
oldPrice: 89.99
}, {
id: 5,
num: 1,
active: false,
isTouchMove: false,
name: '招财猫5',
src: '/img/cat.jpg',
price: 29.99,
oldPrice: 89.99
}, {
id: 6,
num: 1,
active: false,
isTouchMove: false,
name: '招财猫6',
src: '/img/cat.jpg',
price: 69.99,
oldPrice: 89.99
}, {
id: 7,
num: 1,
active: false,
isTouchMove: false,
name: '招财猫7',
src: '/img/cat.jpg',
price: 79.99,
oldPrice: 89.99
}, ],
checkedAll: false,
sumPrice: 0,
subtractDisabled: false,
startX: 0,
startY: 0,
},
onLoad() {
this.getSum();
},
radioChange(e) {
const id = e.currentTarget.dataset.id;
const list = this.data.list;
list.some(item => {
if (item.id === id) {
item.active = !item.active;
return true;
}
})
const flag = this.data.list && (this.data.list.filter(item => item.active)).length === this.data.list.length ? true : false
this.setData({
list,
checkedAll: flag,
}, function () {
this.getSum()
})
},
allSelect() {
const list = this.data.list;
const checkedAll = !this.data.checkedAll;
list.forEach(item => {
item.active = checkedAll;
})
this.setData({
checkedAll: checkedAll,
list,
}, function () {
this.getSum()
})
},
getSum() {
const list = this.data.list;
let sumPrice = 0;
list.forEach(item => {
if (item.active) {
sumPrice += item.price * item.num
}
sumPrice = Number(sumPrice.toFixed(2))
})
this.setData({
sumPrice
})
},
changeNum(e) {
const id = e.currentTarget.dataset.id;
const list = this.data.list;
const type = e.currentTarget.dataset.type;
list.some(item => {
if (item.id === id) {
if (type === "subtract") {
item.num>1?item.num--:wx.showToast({
title: '亲,不能再少啦!',
icon: 'none'
})
} else if (type === "add") {
item.num++
}
return true;
}
})
this.setData({
list
}, function () {
this.getSum()
})
},
inputChange(e) {
const id = e.currentTarget.dataset.id;
const list = this.data.list;
const value = e.detail.value;
list.some(item => {
if (item.id === id && value > 0) {
item.num = value
return true;
}
})
this.setData({
list
}, function () {
this.getSum()
})
},
inputBlur(e) {
const id = e.currentTarget.dataset.id;
const list = this.data.list;
const value = e.detail.value;
if (value === '') {
list.some(item => {
if (item.id === id) {
item.num = 1
return true;
}
})
}
this.setData({
list
}, function () {
this.getSum()
})
},
touchStart(e) {
let list = this.data.list;
list.forEach(item => {
if (item.isTouchMove) {
item.isTouchMove = !item.isTouchMove;
}
});
this.setData({
list: list,
startX: e.touches[0].clientX,
startY: e.touches[0].clientY
})
},
touchMove(e) {
let moveX = e.changedTouches[0].clientX;
let moveY = e.changedTouches[0].clientY;
let indexs = e.currentTarget.dataset.index;
let list = this.data.list;
let angle = this.angle({
X: this.data.startX,
Y: this.data.startY
}, {
X: moveX,
Y: moveY
});
list.forEach((item, index) => {
item.isTouchMove = false;
if (angle > 30) {
return
}
if (indexs === index) {
if (moveX > this.data.startX) {
item.isTouchMove = false;
} else {
item.isTouchMove = true;
}
}
})
this.setData({
list
})
},
angle: function (start, end) {
var _X = end.X - start.X,
_Y = end.Y - start.Y
return 360 * Math.atan(_Y / _X) / (2 * Math.PI);
},
delItem(e) {
let id = e.currentTarget.dataset.id;
let list = this.data.list;
const index = list.findIndex(item => item.id === id);
list.splice(index, 1);
this.setData({
list
}, function () {
this.getSum()
})
}
})