本文主要实现购物车列表右滑删除功能。
一、购物车页面cart.vue
侧滑按钮宽度0.6rem,如果需要体验感好点的可以加个动画属性。
<template>
<div>
<nav-header :showBackBtn="false" @handleBtnClick="goList('searchList')">
<span slot="title">购物车</span>
</nav-header>
<div class="content">
<mescroll-vue
ref="mescroll"
:down="mescrollDown"
:up="mescrollUp"
@init="mescrollInit"
class="mescroll"
v-if="islogin"
>
<div class="cart-wrapper">
<div class="cart-list">
<div
:style="item.deleteSlider"
class="cart-info"
v-for="(item,index) in cartList"
:key="index"
>
<div class="cart-del" @click="isDel(item.id)" v-if="item.disX > 59">删除</div>
<div
class="cart-item space-between"
@touchstart="start($event,item)"
@touchmove="move($event,item)"
@touchend="end($event,item)"
>
<div class="select-wrapper" @click="checkChange(item)">
<div class="select-btn">
<div class="active" v-if="item.checked"></div>
</div>
</div>
<div class="item-img">
<img class="item-img-item" :src="item.goods_pic" />
</div>
<div class="item-info">
<div class="item-name" v-text="item.goods_name"></div>
<div class="item-param">
<span>已选:"</span>
<span v-text="item.spec_name"></span>
<span>" "</span>
<span v-text="item.mat_name"></span>
<span>"</span>
</div>
<div class="item-price">
<span>¥</span>
<span v-text="item.price"></span>
</div>
<div class="select-number-wrapper nowrap">
<div class="btn-del" @click="editBuyNum(item,1)">-</div>
<input class="number" type="number" v-model="item.buy_num" disabled />
<div class="btn-add" @click="editBuyNum(item,0)">+</div>
</div>
</div>
</div>
<div class="cart-param">
<span class="param-count">
共
<span v-text="item.buy_num"></span>
件商品 合计:
</span>
<span class="price" v-text="'¥'+item.price*item.buy_num"></span>
<span class="param-count">运费¥0</span>
</div>
</div>
</div>
<div class="cart-nav space-between">
<div class="select-wrapper" @click="allCheck">
<div class="select-btn">
<div class="active" v-if="cartAllCheck"></div>
</div>
<div class="select-tip">全选</div>
</div>
<div class="cart-total nowrap">
<div class="price-express">
<div class="total-price">
<span class="price-tip">合计:</span>
<span class="price" v-text="'¥' + cartTotalPrice"></span>
</div>
<div class="express">
<span class="express-price">含运费¥0</span>
</div>
</div>
<div class="btn-next" @click="go('ContentPurchasing')">下一步</div>
</div>
</div>
</div>
</mescroll-vue>
<div class="cart-tip" v-else>
<span>请先登录后操作,</span>
<span class="login-tip" @click="go('Login')">立即登录</span>
</div>
</div>
<!-- 确认框 -->
<confirm-dialog :isShow="isShowDialog" @ok="okDiolog" @cancel="close">
<span slot="text" v-text="confirmTips"></span>
</confirm-dialog>
</div>
</template>
<script>
import MescrollVue from "mescroll.js/mescroll.vue";
import ConfirmDialog from "@/components/confirmDialog/ConfirmDialog";
import utils from "@/assets/js/utils";
export default {
components: {
ConfirmDialog,
MescrollVue,
},
data() {
return {
confirmTips: "是否删除该商品",
isShowDialog: false,
id: "",
isdelId: "",
islogin: true,
number: 0,
startX: 0, // 开始pos
endX: 0, // 结束pos
moveX: 0, // 滑动时的pos
disX: 0, // 滑动距离
delTablewidth: 60,
cartList: [],
cartTotalPrice: 0,
cartAllCheck: false,
cartTips: "",
mescroll: null, //mescroll实例对象
//下拉刷新的配置. (如果下拉刷新和上拉加载处理的逻辑是一样的,则mescrollDown可不用写了)
mescrollDown: {
use: false,
},
// 上拉加载的配置.
mescrollUp: {
// auto: false,
callback: this.initCart, // 上拉回调,此处简写; 相当于 callback(page, mescroll) { }
htmlNodata: '<p class="upwarp-nodata">没有更多数据了</p>',
noMoreSize: 0, //如果列表已无数据,可设置列表的总数量要大于0才显示无更多数据;
},
};
},
computed: {},
mounted() {
this.init();
},
methods: {
//mescroll初始化
mescrollInit(mescroll) {
this.mescroll = mescroll;
},
init() {
// 初始化动态添加动画
let userInfo = JSON.parse(localStorage.getItem("userInfo"));
if (!userInfo) {
this.islogin = false;
return;
}
},
initCart(page) {
this.$showLoading();
this.$ajax
.post("Index/getCartGoods", {
size: utils.pageSize,
cp: page.num,
})
.then((res) => {
let resData = res.data;
if (resData.code == "1") {
resData.data.forEach((e) => {
e.goods_pic = utils.fileUrl + e.goods_pic;
e.checked = false;
e.startX = 0; // 开始pos
e.endX = 0; // 结束pos
e.moveX = 0; // 滑动时的pos
e.disX = 0; // 滑动距离
});
if (page.num == 1) {
this.cartList = [];
}
this.cartList = this.cartList.concat(resData.data);
this.$nextTick(() => {
if (!resData.data.length) {
this.mescroll.showNoMore();
} else {
this.mescroll.endSuccess(resData.data.length);
}
});
// this.totalPrice();
} else {
this.mescroll.endSuccess(false);
}
this.$closeLoading();
})
.catch((err) => {
utils.ajaxError(this);
});
},
refresh() {
this.cartList = [];
this.mescroll.resetUpScroll();
},
totalPrice() {
if (this.cartIds().length == 0) {
this.cartTotalPrice = 0;
return;
}
let cartTotalPrice = 0;
this.cartList.forEach((e) => {
if (e.checked == true) {
cartTotalPrice += e.price * e.buy_num;
}
});
this.cartTotalPrice = cartTotalPrice;
},
isDel(id) {
this.id = id;
this.isShowDialog = true;
},
okDiolog() {
this.deleteCartGoods(this.id);
this.close();
},
close() {
this.isShowDialog = false;
this.id = "";
},
deleteCartGoods(id) {
let data = {};
data.cart_id = id;
this.$ajax
.post("Index/deleteCartGoods", data)
.then((res) => {
this.$toast("删除成功");
this.refresh();
this.$closeLoading();
})
.catch((err) => {
utils.ajaxError(this);
});
},
editBuyNum(item, type) {
if (item.buy_num == 1 && type == 1) {
this.$toast("购买数量不能小于1");
return;
}
let data = {};
data.cart_id = item.id;
data.type = type;
this.$ajax
.post("Index/editBuyNum", data)
.then((res) => {
let resData = res.data;
if (resData.code == "1") {
item.buy_num = resData.data.buy_num;
item.total_price = resData.data.total_price;
this.$forceUpdate();
this.totalPrice();
}
this.$closeLoading();
})
.catch((err) => {
utils.ajaxError(this);
});
},
start(e, item) {
e = e || even;
item.startX = 0;
if (e.touches.length === 1) {
item.startX = e.touches[0].clientX;
this.isdelId = item.id;
}
},
end(e, item) {
e = e || even;
if (item.disX < 100) {
item.deleteSlider = "transform:translateX(0px)";
item.disX = 0;
} else {
item.deleteSlider =
"transform:translateX(-" + this.delTablewidth + "px)";
item.disX = 60;
}
for (var i = 0, e; i < this.cartList.length; i++) {
e = this.cartList[i];
if (e.id != this.isdelId) {
e.startX = 0; // 开始pos
e.endX = 0; // 结束pos
e.moveX = 0; // 滑动时的pos
e.disX = 0; // 滑动距离
e.deleteSlider = "transform:translateX(0px)";
}
}
},
move(e, item) {
e = e || even;
if (e.touches.length == 1) {
item.moveX = e.touches[0].clientX;
item.disX = item.startX - item.moveX + item.disX;
if (item.disX > 0) {
if (item.disX < 100) {
item.deleteSlider = "transform:translateX(-" + item.disX + "px)";
} else {
item.deleteSlider = "transform:translateX(-100px)";
}
} else {
if (item.disX < -60) {
item.deleteSlider = "transform:translateX(60px)";
} else {
item.deleteSlider =
"transform:translateX(" + Math.abs(item.disX) + "px)";
}
}
}
},
go(path) {
if (path == "ContentPurchasing") {
if (this.cartIds().length == 0) {
this.$toast("请选择商品");
return;
}
this.order();
} else {
this.$router.push(path);
}
},
goDetail(item) {
let data = {};
data.callId = item.callId;
data.msgFrom = item.msgFrom;
data.prgId = item.prgId;
this.$ajax
.post("common/findMainDetail", data)
.then((res) => {
if (res.data.code == "1") {
this.$router.push({
path: "/appealDetail",
query: {
callId: item.callId,
msgFrom: item.msgFrom,
prgId: item.prgId,
},
});
} else if (res.data.code == "1") {
this.$toast(res.data.msg);
this.$showLoading();
this.$ajax
.post("user/findReceiveMsgList", {
cp: 1,
size: 3,
msgRead: 0,
})
.then((res) => {
let resData = res.data;
if (resData.retcode) {
if (resData.retcode == "0") {
this.msgList = [];
this.msgList = resData.data;
} else {
this.$toast(resData.msg);
}
} else {
this.$toast(utils.ajaxErrorTip);
}
})
.catch((err) => {
this.$toast(utils.ajaxErrorTip);
});
}
this.$nextTick(() => {
this.$closeLoading();
});
})
.catch((error) => {
this.$closeLoading();
});
},
cartIds() {
let cartIds = [];
this.cartList.forEach((e) => {
if (e.checked == true) {
cartIds.push(e.id);
}
});
return cartIds;
},
checkChange(item) {
item.checked = !item.checked;
this.totalPrice();
this.$forceUpdate();
this.cartAllCheck = this.isAllCheck();
},
allCheck() {
let cartList = this.cartList;
for (var i = 0; i < cartList.length; i++) {
cartList[i].checked = !this.cartAllCheck;
}
this.cartAllCheck = this.isAllCheck();
this.totalPrice();
},
isAllCheck() {
let cartList = this.cartList;
for (var i = 0; i < cartList.length; i++) {
if (cartList[i].checked == false) {
return false;
}
}
return true;
},
order() {
this.$showLoading();
let cartIds = this.cartIds(),
list = [];
for (var i = 0; i < cartIds.length; i++) {
let data = {
cart_id: cartIds[i],
};
this.$ajax
.post("Index/order", data)
.then((res) => {
let resData = res.data;
if (resData.code == "1") {
list.push(resData.data.id);
}
if (list.length == cartIds.length) {
// this.deal(list);
this.$router.push({
path: "ContentInfo",
query: {
orderIds: String(list),
},
});
}
})
.catch((err) => {
utils.ajaxError(this);
});
}
},
},
};
</script>
<style scoped lang="less">
@import "~styles/base.less";
.mescroll {
position: fixed;
top: 0.88rem;
// bottom: 0;
.px2rem(bottom, 200);
height: auto;
/deep/.upwarp-nodata,
/deep/.upwarp-tip {
.px2rem(font-size, 24);
.px2rem(line-height, 60);
}
}
.cart-tip {
text-align: center;
.px2rem(line-height, 100);
.px2rem(height, 100);
z-index: 1000;
.login-tip {
color: blue;
}
}
.cart-wrapper {
background-color: #f7f7f7;
// .px2rem(padding-bottom, 200);
.cart-list {
padding: 0.4rem 0.2rem 0;
.cart-info {
transition: 0.2s;
.px2rem(border-radius, 26);
background-color: #fff;
padding: 0 0.2rem;
transform: translateX(0px);
position: relative;
.px2rem(margin-bottom, 40);
.cart-del {
transition: 0.2s;
position: absolute;
.px2rem(width, 100);
.px2rem(line-height, 320);
.px2rem(right, -120);
.px2rem(border-radius, 26);
height: 100%;
top: 0;
background-color: red;
color: #fff;
vertical-align: middle;
text-align: center;
// transform: translateX(-50px);
}
.cart-item {
.px2rem(padding-top, 38);
// .px2rem(margin-bottom, 40);
.select-wrapper {
.px2rem(width, 80);
position: relative;
.select-btn {
.px2rem(width, 32);
.px2rem(height, 32);
box-sizing: border-box;
border: 0.01rem solid #d6d6d6;
border-radius: 50%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
.active {
.px2rem(width, 24);
.px2rem(height, 24);
border-radius: 50%;
background-color: @baseColor;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
}
.item-img {
.px2rem(width, 198);
.px2rem(height, 182);
position: relative;
overflow: hidden;
border: 0.01rem solid #f4f4f4;
.item-img-item {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 100%;
}
}
.item-info {
.px2rem(width, 434);
.px2rem(padding-left, 28);
position: relative;
box-sizing: border-box;
.item-name {
.px2rem(font-size, 28);
.px2rem(line-height, 40);
color: #000;
}
.item-param {
.px2rem(font-size, 24);
.px2rem(line-height, 34);
color: #999;
margin: 0.18rem 0 0.68rem;
}
.item-price {
.px2rem(font-size, 30);
.px2rem(line-height, 40);
color: #ff3131;
}
.select-number-wrapper {
.px2rem(width, 156);
.px2rem(height, 40);
.px2rem(line-height, 40);
.px2rem(font-size, 24);
.px2rem(border-radius, 4);
.px2rem(right, 0);
.px2rem(bottom, 0);
border: 0.01rem solid #d6d6d6;
box-sizing: border-box;
overflow: hidden;
text-align: center;
position: absolute;
.btn-del,
.btn-add {
color: #d6d6d6;
.px2rem(width, 44);
}
.number {
text-align: center;
.px2rem(width, 68);
color: #000;
border-left: 0.01rem solid #d6d6d6;
border-right: 0.01rem solid #d6d6d6;
}
}
}
}
.cart-param {
.px2rem(margin-top, 14);
.px2rem(height, 76);
.px2rem(line-height, 76);
border-top: 0.01rem solid #f4f4f4;
text-align: right;
color: #999;
.param-count {
.px2rem(font-size, 20);
}
.price {
.px2rem(font-size, 24);
}
}
}
}
.cart-nav {
width: 100%;
position: fixed;
background-color: #fff;
border-top: 0.01rem solid #f7f7f7;
.px2rem(left, 0);
.px2rem(bottom, 100);
.px2rem(height, 100);
.px2rem(line-height, 100);
.select-wrapper {
.px2rem(width, 200);
position: relative;
.select-btn {
.px2rem(width, 32);
.px2rem(height, 32);
.px2rem(left, 64);
box-sizing: border-box;
border: 0.01rem solid #d6d6d6;
border-radius: 50%;
position: absolute;
top: 50%;
transform: translateY(-50%);
.active {
.px2rem(width, 24);
.px2rem(height, 24);
border-radius: 50%;
background-color: @baseColor;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
.select-tip {
color: #999;
.px2rem(font-size, 24);
.px2rem(padding-left, 118);
}
}
.cart-total {
.price-express {
.px2rem(line-height, 50);
text-align: right;
.total-price {
.px2rem(margin-top, 10);
.price-tip {
.px2rem(font-size, 20);
color: #999;
}
.price {
color: #ff3131;
.px2rem(font-size, 24);
}
}
.express {
.px2rem(margin-top, -20);
.express-price {
.px2rem(font-size, 20);
color: #999;
}
}
}
.btn-next {
.px2rem(width, 186);
.px2rem(height, 70);
.px2rem(line-height, 70);
.px2rem(border-radius, 35);
.px2rem(font-size, 28);
background-color: @baseColor;
margin: 0.2rem 0.32rem 0 0.22rem;
text-align: center;
color: #fff;
}
}
}
}
</style>