最近使用vant需要实现一个购物车功能,本来准备偷懒网上找一个,最终却没有找到符合需求的;于是自己动手实现了一个 主要实现了:商品的全选、反选以及结算金额的处理 待实现功能:商品数量改变的处理逻辑、购物车商品的编辑
由于后端接口与当前实现的逻辑有所出入,所以将当前逻辑实现记录一下
效果图
使用到的vant组件
import {
CellGroup,
Cell,
Checkbox,
Card,
Sticky,
Stepper,
Overlay,
Loading,
SubmitBar,
} from "vant";
demo源码
<template>
<div class="goods-carts">
<van-overlay
:show="loading"
style="display: flex; align-items: center; justify-content: center;"
>
<van-loading type="spinner" vertical color="#44d9c5" text-color="#44d9c5">
数据加载中……
</van-loading>
</van-overlay>
<div v-if="list.length === 0" class="nodata"></div>
<div v-else>
<van-sticky>
<van-cell :title="'全部商品(2)'">
<span v-if="!editing" style="color: #333;">编辑</span>
<span v-if="editing" style="color: #333;">完成</span>
</van-cell>
</van-sticky>
<div class="carts-item">
<van-cell-group v-for="item in list" :key="item.id" class="item-group">
<van-cell :border="false" :title="item.shopName" icon="shop-o" />
<van-cell style="padding:0" :border="false">
<van-checkbox
v-for="goods in item.goods"
:key="goods.id"
:value="checkedIds.includes(goods.id)"
checked-color="#44d9c5"
class="item-box"
:label-disabled="true"
@click="checkItem(goods)"
>
<van-card
:price="goods.price"
:title="goods.goodsName"
:thumb="goods.goodsImg"
>
<template #num>
<van-stepper
v-model="goods.num"
:max="goods.maxNum"
integer
style="margin-top: -2vw;"
@change="handleChangeNum"
@click.native.stop="() => {}"
/>
</template>
</van-card>
</van-checkbox>
</van-cell>
</van-cell-group>
</div>
<div class="carts-sub">
<van-submit-bar
:price="subPrice"
button-text="结 算"
button-color="#44d9c5"
@submit="onSubmit"
>
<van-checkbox
v-model="checked"
checked-color="#44d9c5"
@change="checkAll"
>
全选
</van-checkbox>
</van-submit-bar>
</div>
</div>
</div>
</template>
<script>
import _ from "lodash";
import {
CellGroup,
Cell,
Checkbox,
Card,
Sticky,
Stepper,
Overlay,
Loading,
SubmitBar,
} from "vant";
export default {
components: {
[CellGroup.name]: CellGroup,
[Cell.name]: Cell,
[Checkbox.name]: Checkbox,
[Card.name]: Card,
[Sticky.name]: Sticky,
[Stepper.name]: Stepper,
[Overlay.name]: Overlay,
[Loading.name]: Loading,
[SubmitBar.name]: SubmitBar,
},
data() {
return {
editing: false,
loading: false,
checked: false,
subPrice: 0,
list: [],
canCheckNum: 0,
checkedIds: [],
};
},
created() {
this.getList();
},
methods: {
handleChangeNum(val) {
console.log(1111111, val);
},
getList() {
this.loading = true;
setTimeout(() => {
this.list = [
{
id: 1,
shopName: "北京大学人民医院",
goods: [
{
id: "EYE_1001",
goodsName: "护眼仪",
num: 2,
maxNum: 10,
price: 200,
goodsImg: "https://img.yzcdn.cn/vant/ipad.jpeg",
},
{
id: "EYE_1002",
goodsName: "眼药水",
num: 1,
maxNum: 200,
price: 25,
goodsImg: "https://img.yzcdn.cn/vant/ipad.jpeg",
},
],
},
{
id: 2,
shopName: "测试医院1",
goods: [
{
id: "EYE_1003",
goodsName: "眼睛框",
num: 2,
maxNum: 500,
price: 10,
goodsImg: "https://img.yzcdn.cn/vant/ipad.jpeg",
},
],
},
];
_.map(this.list, (item) => {
_.map(_.get(item, "goods", []), () => {
this.canCheckNum++;
});
});
this.loading = false;
}, 3000);
},
checkItem(goods) {
if (this.checkedIds.includes(goods.id)) {
this.checkedIds = _.filter(this.checkedIds, (id) => id !== goods.id);
this.subPrice -= goods.price * 100 * goods.num;
this.checked = false;
} else {
this.checkedIds.push(goods.id);
this.subPrice += goods.price * 100 * goods.num;
}
if (this.checkedIds.length === this.canCheckNum) {
this.checked = true;
}
},
checkAll(val) {
if (val) {
if (this.checkedIds.length !== this.canCheckNum) {
_.map(this.list, (item) => {
_.map(_.get(item, "goods", []), (goods) => {
this.checkedIds.push(goods.id);
this.subPrice += goods.price * 100 * goods.num;
});
});
}
} else {
if (this.checkedIds.length === this.canCheckNum) {
this.checkedIds = [];
this.subPrice = 0;
}
}
},
onSubmit() {},
},
};
</script>
<style lang="less">
.goods-carts {
.van-submit-bar__button--danger {
background: #44d9c5;
border: none;
}
.carts-item {
.item-group {
margin: 3vw 0;
.item-box {
padding: 2vw 4vw;
.van-checkbox__label {
width: 100%;
}
}
}
}
}
</style>
注:当前源码可直接使用,查看效果;有兴趣的小伙伴可以将剩余功能进行实现