购物车
1. 购物车
1.1 布局样式
固定定位 position:fixed;
1.2 购物车交互
第一步:在获取到商品数据后,给每一个商品添加一个数量属性,用于记录商品的购物数量
//给每一个商品添加一个购物数量的属性
res.data.data.forEach(v=>{
v.foods.forEach(v2=>{
v2.cartNum=0;
});
});
第二步:将商品列表添加到vuex,用于计算购物车商品列表
export default new Vuex.Store({
state: {
goodsList:[], //商品列表
cartList:[], //购物车列表
},
mutations: {
//存储商品列表
addGoods(state, payload){
state.goodsList = payload;
},
},
})
第三步:点击加减时计算购物车商品
mutations: {
//计算购物车商品数量
addCart(state, payload){
let arr=[];
state.goodsList.forEach(v=>{
v.foods.forEach(v2=>{
//遍历所有商品,商品购物车数量大于0,添加到购物车
if(v2.cartNum>0){
arr.push(v2); //为了防止商品重复叠加,所以需要用一个临时变量进行计算存储
}
})
})
state.cartList = arr; //替换掉以前的
}
},
第四步:根据购物车商品数量显示样式
<!--购物车图标-->
<van-badge :content="cartList.length" v-if="cartList.length>0">
<van-icon name="shopping-cart" class="active"/>
</van-badge>
<van-icon name="shopping-cart" v-else/>
<!--去结算-->
<div :class="{active: cartList.length>0}">
<span v-if="cartList.length>0">去结算</span>
<span v-else>¥20元起送</span>
</div>
第五步:计算商品总价
//计算购物车商品总价
total(){
let sum=0;
this.cartList.forEach(v=>{
sum+=v.cartNum * v.price;
})
return sum;
},
第六步:渲染购物车商品列表
//清空购物车
clearCart(state, payload){
state.cartList = [];
//清空商品列表中所有购物数量
state.goodsList.forEach(v=>{
v.foods.forEach(v2=>{
v2.cartNum=0;
})
})
}
1.3 数据跨页面共享的问题
问题:vuex的数据可以实现跨页面共享,页面切回来时会重新发请求获取数据,并写入vuex,数据被覆盖
解决:在发请求前,判断一下vuex里面有没有数据,如果有就不发请求,如果没有就要发请求
//判断当前vuex里面有没有数据,如果没有就发请求
if(this.list.length===0){
//获取商品信息
let res = await goodsList();
//给每一个商品添加一个购物数量的属性
res.data.data.forEach(v=>{
v.foods.forEach(v2=>{
v2.cartNum=0;
});
});
//将读取到的数据存储到vuex
this.$store.commit('addGoods', res.data.data);
}
代码具体实现:
<template>
<!-- 购物车的独立组件 -->
<div>
<div class="cart">
<div><van-icon name="smile-o" />联系商家</div>
<div @click="show=!show">
<van-badge :content="cartList.length" v-if="cartList.length>0">
<van-icon name="shopping-cart" class="active"/>
</van-badge>
<van-icon name="shopping-cart" v-else/>
</div>
<div>
<strong>¥{{total | fixed}}</strong>
另需配送费¥4元 | 支持自取
</div>
<div :class="{active: cartList.length>0}">
<span v-if="cartList.length>0">去结算</span>
<span v-else>¥20元起送</span>
</div>
</div>
<van-popup v-model="show" round position="bottom">
<h3>新用户下单立减5元</h3>
<div class="opt"><strong>购物车</strong> <span @click="clear"><van-icon name="delete-o" /> 清空购物车</span></div>
<ul>
<li v-for="(v,i) in cartList" :key="i">
<div class="title">{{v.name}}</div>
<strong>¥{{v.cartNum*v.price | fixed}}</strong>
<van-stepper v-model="v.cartNum" theme="round" button-size="20" disable-input />
</li>
</ul>
</van-popup>
</div>
</template>
<script>
import {mapState} from 'vuex';
export default {
data(){
return {
show:false,
}
},
methods:{
//清空购物车
clear(){
this.$store.commit('clearCart');
this.show=false;
}
},
computed:{
...mapState(['cartList']), //辅助函数读取vuex购物车数据
//计算购物车商品总价
total(){
let sum=0;
this.cartList.forEach(v=>{
sum+=v.cartNum * v.price;
})
return sum;
},
},
filters:{
//保留两位小数的过滤器
fixed(n){
return n.toFixed(2);
}
}
}
</script>
<style lang="less" scoped>
.cart{
position:fixed;
bottom:10px;
z-index:99999;
left:3%;
width:94%;
height:60px;
display:flex;
background:#222;
color:#999;
font-size:12px;
border-radius:30px;
overflow:hidden;
&>div:nth-child(1){
width:66px;
border-right:3px solid #fff;
text-align:center;
.van-icon{
font-size:24px;
display:block;
padding-top:6px;
}
}
&>div:nth-child(2){
width:60px;
.van-icon{
font-size:35px;
background:#333;
padding:8px;
border-radius:100%;
margin:5px;
}
.active{
background:#ffc300;
color:#000;
}
:deep(.van-badge--fixed){
top:12px;
right:10px;
}
}
&>div:nth-child(3){
font-size:12px;
padding-top:12px;
flex-grow:1;
strong{
display:block;
color:#fff;
font-size:20px;
}
}
&>div:nth-child(4){
line-height:60px;
width:66px;
}
&>div:nth-child(4).active{
background:#ffc300;
color:#000;
text-align:center;
font-size:16px;
}
}
.van-popup{
padding-bottom:80px;
h3{
text-align:center;
font-weight:normal;
color:#e04c1f;
background:#fee7c8;
line-height:32px;
font-size:14px;
}
.opt{
display:flex;
justify-content:space-between;
line-height:30px;
padding:0 10px;
}
ul{
padding:10px;
li{
display:flex;
padding:10px 0;
.title{
width:1px;
flex-grow:1;
overflow:hidden;
white-space:nowrap;
text-overflow:ellipsis;
}
strong{
width:80px;
color:#f00;
}
}
}
}
</style>
vuex数据
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
goodsList:[], //商品列表
cartList:[], //购物车列表
},
getters: {
},
mutations: {
//存储商品列表
addGoods(state, payload){
state.goodsList = payload;
},
//计算购物车商品数量
addCart(state, payload){
let arr=[];
state.goodsList.forEach(v=>{
v.foods.forEach(v2=>{
//遍历所有商品,商品购物车数量大于0,添加到购物车
if(v2.cartNum>0){
arr.push(v2); //为了防止商品重复叠加,所以需要用一个临时变量进行计算存储
}
})
})
state.cartList = arr; //替换掉以前的
},
//清空购物车
clearCart(state, payload){
state.cartList = [];
//清空商品列表中所有购物数量
state.goodsList.forEach(v=>{
v.foods.forEach(v2=>{
v2.cartNum=0;
})
})
}
},
actions: {
},
modules: {
}
})
推荐阅读:
扫描二维码,在手机上阅读