【3D商城】使用Vuex状态管理完成购物车模块
创建购物车的全局数据
在store的index.js中 ,创建购物车变量
state() {
return {
count: 0,
isFullscreen: false, //默认不是全屏状态
buycarts: [], //购物车变量
};
}
添加产品到购物车
mutations: {
addBuycarts(state, payload) { //添加产品到购物车
state.buycarts.push(payload);
},
addBuycartsNum(state, payload) { //添加购物车商品的数量
state.buycarts[payload].num++;
},
minusBuycartsNum(state, payload) { //减少购物车商品数量
state.buycarts[payload].num--;
if (state.buycarts[payload].num == 0) {
state.buycarts.splice(payload, 1);
}
}
}
计算总价
getters: {
totalPrice(state) {
let total = state.buycarts.reduce((pre, item) => {
return pre + item.price * item.num;
}, 0);
return total;
},
}
产品页面组件 添加商品
<div class="products">
<div
class="prod-item"
:class="{ active: pI == data.pIndex }" //判断现在的索引值是否为选中索引值相同,相同active为true
v-for="(prod, pI) in data.products"
@click="changeModel(prod, pI)"
>
<div class="prod-title">
{{ prod.title }}
</div>
<div class="img">
<img :src="prod.imgsrc" :alt="prod.title" />
</div>
<a-button type="primary" block @click.stop="addBuycart(prod)">
<template #icon>
<ShoppingCartOutlined></ShoppingCartOutlined>
</template>
加入购物车
</a-button>
</div>
事件后面添加.stop可以在点击填入购物车后,阻止触发changeModel()函数,阻止向上传递,@click.stop="addBuycart(prod)"
调用addBuycart()方法
function addBuycart(prod) {
let product = { ...prod, num: 1 }; //解构产品并初始化数量为1
let index = 0;
let isExist = store.state.buycarts.some((item, i) => {
if (product.id == item.id) {
index = i;
return true;
} else {
return false;
}
});
if (isExist) {
store.commit("addBuycartsNum", index); //提交
} else {
store.commit("addBuycarts", product);
}
}
导航栏的购物车模块
左侧列表的产品数据会传递到Header中的购物车列表中,并计算总价
<a-menu-item-group title="购物商品">
<a-menu-item v-for="(item, i) in store.state.buycarts" :key="item.id">
<div class="prod-item">
<div class="left">
<img :src="item.imgsrc" :alt="item.title" />
</div>
<div class="middle">
<div class="title">{{ item.title }}</div>
<div class="content">
<span class="num">数量:{{ item.num }}</span>
<div class="control">
<span
class="btn"
@click.stop="store.commit('addBuycartsNum', i)"
>+</span
>
<span
class="btn"
@click.stop="store.commit('minusBuycartsNum', i)"
>-</span
>
</div>
</div>
</div>
<div class="right">
<div class="price">¥ {{ item.price * item.num }}</div>
</div>
</div>
</a-menu-item>
<a-menu-item key="totalPrice">
<div class="total">
<span>总价:</span>
<span class="num"> ¥ {{ store.getters.totalPrice }}</span>
</div>
</a-menu-item>
</a-menu-item-group>
左边是图片、中间是内容(产品的名称、数量、按钮)、右边是产品价格下面是总价,对图片的大小按钮,进行调整 ,购物车的内容一般不会在Product一个组件中显示,全局数据写在App组件中,样式如下:
.ant-menu-submenu {
z-index: 1000000000 !important; //优先级最高
}
body .ant-menu-sub .ant-menu-item {
height: auto; //高度自动随着盒子变化
}
.ant-menu-sub .ant-menu-item .prod-item {
display: flex;
width: 400px;
justify-content: space-between;
}
.ant-menu .prod-item img { //图片
width: 100px;
height: 100px;
}
.ant-menu-item .prod-item .middle { //中间分布
width: 220px;
height: 100px;
display: flex;
flex-direction: column;
justify-content: space-between; // 两边靠
}
.ant-menu-item .prod-item .middle .title {
font-size: 16px;
font-weight: 900;
}
.ant-menu-item .prod-item .middle .content {
display: flex;
justify-content: space-between;
}
.ant-menu-item .prod-item .middle .btn { //按钮
display: inline-block;
width: 30px;
height: 30px;
text-align: center;
line-height: 30px;
border: 1px solid #ccc;
margin: 0 5px;
}
.ant-menu-item .prod-item .right .price { //价格
font-weight: 900;
color: orange;
font-size: 16px;
display: flex;
justify-content: center;
align-items: center;
}
.ant-menu-item .total { //总价
font-weight: 900;
display: flex;
justify-content: flex-end;
font-size: 16px;
}
.ant-menu-item .total .num {
color: orange;
padding-right: 20px;
}
结果
最终结果显示如下:
点击左侧商品按钮会在导航栏显示,增加各种商品的数量,总价会随着数量一起改变
常见问题总结
连续点击左侧的添加购物车时,导航栏的购物车模块会添加多个产品,如果是同一件商品,其实只要改变数量即可,问题如下
需要在addBuycart()方法中增加一个判断,判断添加的产品是否已经存在,some()用来检测是否有满足条件,判断当前选中的产品的id是否和购物车中任何一个产品的id重复,如果重复则只增加数量,不重复则增加商品
let index = 0;
let isExist = store.state.buycarts.some((item, i) => {
if (product.id == item.id) {
index = i;
return true;
} else {
return false;
}
});
if (isExist) {
store.commit("addBuycartsNum", index);
} else {
store.commit("addBuycarts", product);
}