一、应用场景
移动端我们经常会遇到需要左滑删除列表中某一项的场景,效果如下图:
二、代码实现
具体实现代码如下,可直接运行查看效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>移动端-左滑删除案例</title>
<script src="https://cdn.staticfile.net/vue/2.7.0/vue.min.js"></script>
<style>
body,
p {
margin: 0;
padding: 0;
}
.flex-between {
display: flex;
justify-content: space-between;
align-items: center;
}
.flex-colum-between {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.flex-1 {
flex: 1;
}
.center {
display: flex;
justify-content: center;
align-items: center;
}
.header {
font-size: 18px;
font-weight: 600;
height: 44px;
line-height: 44px;
text-align: center;
color: #fff;
background: #3C8CFF;
}
.goods-box {
overflow: hidden;
}
.goods-item {
transition: all 0.2s;
}
/* =0隐藏 */
.goods-item[data-type="0"] {
transform: translate3d(0, 0, 0);
}
/* =1显示 */
.goods-item[data-type="1"] {
transform: translate3d(-62px, 0, 0);
}
.goods-info {
position: relative;
display: flex;
padding: 8px 16px;
border-bottom: 1px solid #ccc;
box-sizing: border-box;
}
.goods-info img {
width: 88px;
height: 88px;
margin-right: 8px;
border-radius: 8px;
background: #ccc;
}
.goods-info .name {
font-size: 12px;
font-weight: 600;
line-height: 16px;
color: #323233;
}
.goods-info .des,
.goods-info .total {
font-size: 12px;
line-height: 16px;
color: #969799;
}
.goods-info .price {
font-size: 16px;
font-weight: 600;
line-height: 18px;
color: #323233;
}
.goods-info .removeBtn {
position: absolute;
right: -62px;
top: 0;
height: 100%;
width: 60px;
color: #fff;
background: #ee0a24;
}
</style>
</head>
<body>
<div id="app">
<div class="header">左滑删除案例</div>
<div class="goods-box">
<div class="goods-item" v-for="(goods,idx) in goodsList" data-type="0">
<div class="goods-info" @touchstart.capture="touchStart" @touchend.capture="touchEnd" @click="oneself">
<img :src="goods.img" alt="加载失败" />
<div class="flex-1 flex-colum-between">
<div>
<p class="name">{{goods.name}}</p>
<p class="des">{{goods.des}}</p>
</div>
<div class="flex-between">
<span class="price">¥{{goods.price}}</span>
<span class="total">x{{goods.total}}</span>
</div>
</div>
<div class="removeBtn center" @click="remove(idx)">删除</div>
</div>
</div>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
startX: 0, //滑动开始
endX: 0, //滑动结束
goodsList: [{
name: '商品标题-1',
price: '1.00',
des: '描述信息-1',
total: 1,
img: 'https://fastly.jsdelivr.net/npm/@vant/assets/ipad.jpeg'
},
{
name: '商品标题-2',
price: '2.00',
des: '描述信息-2',
total: 2,
img: 'https://fastly.jsdelivr.net/npm/@vant/assets/ipad.jpeg'
},
{
name: '商品标题-3',
price: '3.00',
des: '描述信息-3',
total: 3,
img: 'https://fastly.jsdelivr.net/npm/@vant/assets/ipad.jpeg'
},
{
name: '商品标题-4',
price: '4.00',
des: '描述信息-4',
total: 4,
img: 'https://fastly.jsdelivr.net/npm/@vant/assets/ipad.jpeg'
}
]
},
methods: {
//滑动开始
touchStart(e) {
this.startX = e.touches[0].clientX; // 记录初始位置
},
//滑动结束
touchEnd(e) {
// 当前滑动的父级元素
let parentElement = e.currentTarget.parentElement;
// 记录结束位置
this.endX = e.changedTouches[0].clientX;
// 左滑大于30距离删除出现
if (parentElement.dataset.type == 0 && this.startX - this.endX > 30) {
this.restSlide();
parentElement.dataset.type = 1;
}
// 右滑
if (parentElement.dataset.type == 1 && this.startX - this.endX < -30) {
this.restSlide();
parentElement.dataset.type = 0;
}
this.startX = 0;
this.endX = 0;
},
//判断当前是否有滑块处于滑动状态
checkSlide() {
let listItems = document.querySelectorAll(".goods-item");
for (let i = 0; i < listItems.length; i++) {
if (listItems[i].dataset.type == 1) {
return true;
}
}
return false;
},
// 向左滑动出现删除按钮时,点击商品信息区域取消删除
oneself() {
if (this.checkSlide()) {
this.restSlide();
} else {
// 点击商品信息弹出弹框
console.log("点击当前商品触发事件...");
}
},
//复位滑动状态
restSlide() {
let listItems = document.querySelectorAll(".goods-item");
// 复位
for (let i = 0; i < listItems.length; i++) {
listItems[i].dataset.type = 0;
}
},
//删除数据信息
remove(idx) {
this.restSlide(); // 复位
this.goodsList.splice(idx, 1); // 删除数组lists中一个数据
},
//
},
})
</script>
</body>
</html>