1、實作清單資料和底部購物車資料共享:
(1)vuex的state添加一個屬性,用來存儲購物車清單的資料,購物車清單的每一項都是商品對象
(2)當點選增加按鈕時,往目前商品對象中添加count資料:
利用vuex,當點選增加/減少按鈕時,将目前物品對象中添加一個count屬性,
因為是對象的引用關系,如果vuex之前的state狀态中已經存在商品清單的資料,無需再添加額外的state狀态,
目前對象改變屬性(利用Vue.set,将對象的新屬性交給vue來動态綁定資料),商品清單中的該元素也會相應改變
添加count屬性後,即可根據加減來改變count屬性的值,進而實作獲得該商品的數量
(3)vuex建立對應的方法來進行第(2)步
actions.js中建立方法來調用mutations.js内的方法來使得狀态增/減,方法的傳入目前對象
調用actions.js:this.$store.dispatch('xx',{對象:xx});
actions.js: xx({commit},{對象})
{
commit(RECEIVE_XXX,{對象});
},
mutations.js:
[RECEIVE_XXX](state,{對象})
{
if(對象.count)
{
food.count++;
}else{
state.購物車清單.push(對象); //增加時往購物車清單添加該商品對象,相同商品隻改變了count屬性,是以每個商品隻需要添加一次
Vue.set(對象,'count',1); //讓對象新增的資料能夠被vue資料綁定,動态更新
}
}
(4)通過state中的購物車清單的内容,實作底部購物車的資料展示
因為需要實時更新,且建立在已有資料state上
在getters.js中定義計算屬性方法,通過周遊購物車清單的每一個對象中的count,來計算數量和總價
totalCount(state)
{
return state.購物車清單.reduce((preTotal,food)=>{return preTotal+food.count},0)
},
totalPrice(state)
{
return state.購物車清單.reduce((preTotal,food)=>{return preTotal+food.count*food.price},0)
}
(5)将vuex狀态引入到元件,實作對應功能
(6)清除購物車
周遊購物車清單,将所有對象的count屬性值置為0,然後将整個清單置空(=[ ])
對象的引用:
多個對象引用同一個對象,其中一個改變,都會改變
多個對象引用同一個對象,其中一個指向另一個對象,其他對象不變
代碼示例:
state.js:
export default{
address:"", //位址
categorys:[],//食品分類
shops:[],//商家
userInfo:{}, //使用者資訊
goods:[], //商品清單
ratings:[], //商家評價
info:[] ,//商家資訊
cartFoods:[] //購物車中的商品清單
}
actions.js
import {
RECEIVE_ADDRESS,
RECEIVE_CATEGORYS,
RECEIVE_SHOPS,
RECEIVE_USERINFO,
RECEIVE_RESET,
RECEIVE_GOODS,
RECEIVE_RATINGS,
RECEIVE_INFO,
RECEIVE_ADD,
RECEIVE_DELETE
} from './mutation-types'
import axios from 'axios';
export default{
//同步更新food中的count數量,增加
updateFoodCount({commit},{food})
{
commit(RECEIVE_ADD,{food});
},
//同步更新food中的counte數量,減少
updateFoodCountDelete({commit},{food})
{
commit(RECEIVE_DELETE,{food});
}
}
mutations.js:
import {
RECEIVE_ADDRESS,
RECEIVE_CATEGORYS,
RECEIVE_SHOPS,
RECEIVE_USERINFO,
RECEIVE_RESET,
RECEIVE_GOODS,
RECEIVE_RATINGS,
RECEIVE_INFO,
RECEIVE_ADD,
RECEIVE_DELETE
} from './mutation-types'
import Vue from 'vue'
export default{
[RECEIVE_ADD](state,{food})
{
if(food.count)
{
food.count++;
}else{
state.cartFoods.push(food); //增加時往購物車清單添加該商品對象,相同商品隻改變了count屬性,是以每個商品隻需要添加一次
Vue.set(food,'count',1); //讓對象新增的資料能夠被vue資料綁定,動态更新
}
},
[RECEIVE_DELETE](state,{food})
{
if(food.count)
{
food.count--; //對象引用,使得屬性值減1
if(food.count==0)
{
state.cartFoods.splice(state.cartFoods.indexOf(food),1);
}
}
}
}
getters.js:
export default{
totalCount(state) //傳回數量
{
return state.cartFoods.reduce((preTotal,food)=>{return preTotal+food.count},0)
},
totalPrice(state)//傳回總價
{
return state.cartFoods.reduce((preTotal,food)=>{return preTotal+food.count*food.price},0)
}
}
頁面:
<template>
<div class='bf'>
<transition name='wave'>
<div class='blist' v-show='show'> //展開清單
<div class='b1'>
<span>購物車</span>
<span>清空</span>
</div>
//展開清單,根據購物車清單的狀态中是否有資料來渲染
<ul class='b2' v-for='(item,index) in cartFoods' :key='index' >
<li class='b3'>
<span>{{item.name}}</span>
<div class='b4'>
<span>¥{{item.price}}</span>
<div class='lz'>
<div class='cir' @click='del(item)'>
-
</div>
<span class='cp'>{{item.count}}</span>
<div class='cir' @click='add(item)'>
+
</div>
</div>
</div>
</li>
</ul>
</div>
</transition>
<div class='bs'>
<div class='bl'>
<div class='bimg' @click='change'>
<img src="./imgs/1.png" alt="">
</div>
<div class='binfo'>
<p>¥{{totalPrice}}元</p> //根據vuex的計算屬性傳回總價
<p>另需配送費¥{{info.deliveryPrice}}元</p>
</div>
</div>
<div class='br' :class='{on:totalPrice>=info.minPrice}'>//根據vuex的計算屬性計算價錢
{{totalPrice?totalPrice>=info.minPrice?'去結算':'還差'+(info.minPrice-totalPrice)+'元起送':`¥${info.minPrice}元起送`}}
</div>
<!-- 購物車圖示上的數量提示,根據vuex的購物車清單是否有值顯示 -->
<div class='balert' v-show='totalCount'>
{{totalCount}}
</div>
</div>
</div>
</template>
<script>
import {mapState,mapGetters} from 'vuex';
export default {
data()
{
return{
show:false
}
},
methods: {
change() {
this.show=!this.show;
},
del(food) //減少count
{
this.$store.dispatch('updateFoodCountDelete',{food})
},
add(food) //增加count
{
this.$store.dispatch('updateFoodCount',{food})
}
},
computed: {
...mapState(['cartFoods','info']),
...mapGetters(['totalCount','totalPrice'])
}
}
</script>
<style lang='less'>
.on{
background-color: #44BB00!important;
}
.bf{
width: 100%;
position: fixed;
bottom: 0px;
.blist{
background-color:#F3F5F7;
.b1{
display: flex;
justify-content: space-between;
padding: 0 20px;
height: 40px;
line-height: 40px;
border: solid 1px #ccc;
span:last-child{
padding: 0 10px;
border-left: solid 1px #ccc;
border-right: solid 1px #ccc;
}
}
.b2{
padding-bottom: 10px;
background-color: white;
.b3{
height: 30px;
line-height: 30px;
border-bottom:solid 1px #ccc;
padding:0 20px ;
display: flex;
justify-content: space-between;
.b4{
display: flex;
>span{
color:red
}
.lz{
display: flex;
width: 70px;
justify-content: space-evenly;
align-items: center;
.cir{
text-align: center;
line-height: 20px;
width: 20px;
height: 20px;
color: white;
background-color: #008000;
border-radius: 100px;
}
.cp{
font-size: 10px;
}
}
}
}
}
}
.bs{
color: white;
background-color: #131D29;
height: 50px;
width: 100%;
display: flex;
justify-content: space-between;
position: relative;
.bl{
display: flex;
.bimg{
height: 45px;
width: 45px;
border-radius: 100px;
margin-top: -10px;
background-color: #131D29;
text-align: center;
font-size: 0px;
line-height: 45px;
margin-left: 20px;
img{
height: 40px;
width: 40px;
vertical-align: middle;
}
}
.binfo{
display: flex;
flex-direction: column;
justify-content: space-around;
margin-left: 10px;
p:last-child{
color:#ccc;
font-size: 12px;
}
}
}
.br{
height: 50px;
line-height: 50px;
background-color: #2B333D;
padding:0 10px;
color: white;
}
.balert{
background-color: red;
height: 20px;
width: 20px;
line-height: 20px;
border-radius: 100px;
text-align: center;
position: absolute;
left: 45px;
top:-10px;
}
}
}
.wave-enter-to,.wave-leave{
transform:translateY(0)
}
.wave-enter,.wave-leave-to{
transform:translateY(100%)
}
.wave-enter-active,.wave-leave-active{
transition: transform 1s;
}
</style>
效果圖: