一、前言
在上篇購物車中,如果用戶刷新了當前的頁面,底部導航中的數據又會恢復為原來的:
1、解決刷新,購物車上數值不變
2、在購物車點擊加減按鈕,數值做出對應變化
二、主要內容
1、實現效果:點擊購物車的時候可以查看到購物車的商品信息
2、解決刷新,購物車上數值不變
(1)新建一個Cart.vue展示購物信息,並將路由添加到index.js中
(2)購物車里面涉及到:存儲商品信息,獲取商品信息,保存商品信息,這里將這些方法單獨封裝到一個.js文件中(本來需要在后台操作)
let obj={}; //定義一個對象,存儲商品信息 //這里需要存儲數據 //{商品的id, 商品的數量} //保存商品 obj.saveGoods = function(goodsList){ window.localStorage.setItem('goodsList',JSON.stringify(goodsList)) } //獲取商品的值 obj.getGoodsList = function(){ return JSON.parse(window.localStorage.getItem('goodsList'|| '{}'))//如果stroge中沒有值,返回一個空對象 } //增加商品 obj.add = function(goods){ let goodsList = this.getGoodsList()//獲取到storage里面的對象 if(goodsList[goods.id]){ //goods.id是商品的數量,對應有值的話就追加 goodsList[goods.id] = goodsList[goods.id] + goods.num; }else{ goodsList[goods.id]=goods.num; } //傳進來之后還需要保存 this.saveGoods(goodsList); } //獲取購物車的總數量 obj.getTotalCount = function(){ let goodsList = this.getGoodsList(); let values = Object.values(goodsList);//Object.values返回的是一個數組,里面對應着每一個key的value let sum = 0; values.forEach(val => sum = sum +val); return sum; } export default obj;
(2)封裝好了方法就要在商品詳情頁面使用(類似於我們在淘寶上買東西,當你在商品詳情頁面點擊加入購物車之后,購物車里面會有對應的商品)
name:'GoodsDetail', data(){ return{ url:`getthumImages/${this.$route.params.id}`, goodsInfo:{},//當前購物車的信息,里面有id pickNum:1 , isExist:false //讓小球默認是隱藏的狀態, } }, methods:{ afterEnter(){ this.isExist=false; //顯示出來之后執行這個,又將小球隱藏 this.$bus.$emit('sendPickNum',this.pickNum); //當觸發了上面的事件之后, GoodsTool.add({ id:this.goodsInfo.id, num:this.pickNum }) }, //點擊加入購物車執行這個方法,然后讓小球顯示出來 ballHandler(){ this.isExist=true; // this.$bus.$emit('sendPickNum',this.pickNum); //將當前的pickNum傳過去,但是這個不能加在這里,否者一點擊“加入購物車就傳 },
(3)當你一刷新,stroge里面的數據清空,下面的購物車上面的數值又變成0了,所以在下面的底部導航里,讓他一開始就獲取到當前這個總數
created(){ //當你的組件一創建好了后就掛載這個bus公交車,$on這個事件監聽 this.$bus.$on(`sendPickNum`, (data)=>{ this.pickNum=this.pickNum + data; / }), this.pickNum=GoodsTool.getTotalCount();//直接將這Goods.vue里面傳來的數據賦值, }
(4)通過以上思路,就能保證刷新頁面時,購物車中的數據不發生改變
3、點擊底部導航“購物車”,將上面加進的東西和數量展示在頁面中,(在購物車點擊加減按鈕,數值做出對應變化)
(1)首先發送請求,這里發送請求的時候,需要之后再購物詳情頁面加入的商品的id, 然后根據對應的id拿到對應的請求數據
(2)拿到購物詳情里面的id
let goodsList = GoodsTool.getGoodsList();//["88":5,"99":4] 第一個數商品id 第二個是商品數量 let ids = Object.key(goodsList).join(',');//Object.key()獲取key值 [88,99]
(3)拿到上面的id之后就可以發請求
created(){ let goodsList = GoodsTool.getGoodsList();//{"88":5,"99":4} 第一個數商品id 第二個是商品數量 let ids = Object.key(goodsList).join(',');//Object.key()獲取key值 [88,99] if(ids){ this.$axios.get(`goods/getshopcarlist${ids}`) .then(res=>{ this.shopCart=res.data.message; } }) }
(4)但是這里的后端數據庫里並沒有保存加入購物車的數量(如果有可以直接從后端獲取),這里手動添加
created(){ let goodsList = GoodsTool.getGoodsList();//{"88":5,"99":4} 第一個數商品id 第二個是商品數量 let ids = Object.key(goodsList).join(',');//Object.key()獲取key值 [88,99] if(ids){ this.$axios.get(`goods/getshopcarlist${ids}`) .then(res=>{ this.shopCart=res.data.message;//返回的是一個數組 //給數組元素添加屬性 for(var i=0; i<this.shopCart.length;i++){ let shop=this.shopCart[i];//獲取到當前的對象 let num = goodsList[shop.id];//根據當前對象的id查找到對應的購物車數量 shop.num = num;//給每個對象添加一個num屬性,並在視圖上渲染,但是會發現視圖上的值並沒有改變 } } }) }
(5)在購物車列表做加減操作,並且將當前的對象傳進去
<li class="p-list" v-for="(shop, index) in shopCart"> <mt-switch></mt-switch> <img src=""> <div class="pay-calc"> <p>{{shop.title}}</p> <div class="calc"> <span>¥777</span> <span @click="substract(shop)">-</span> <span>{{shop.num}}</span> <span @click="addNum(shop)">+</span> <a href="javascript:;">刪除</a> </div> </div> </li>
methods:{ addNum(shop){//每次點擊都接受到當前的對象 shop.num++; //這里的值雖然加上了,但是,數據並沒有響應上去,是因為created是一開始就加載的,后來點擊修改了num的值,但是沒有 響應視圖 console.log(shop) }, substract(shop){ if(shop.num==1){ return; } shop.num--; } },
(6)做完第五步,在測試的時候,發現控制台中打印出來的對象中num改變,但是視圖上並沒有改變
原因:vue 中存在一種機制會將shopCart(也就是你請求的數據進行監視)屬性進行監視,完成響應式(因為后面的num是我們自己加進去的,沒有掛載到數據屬性里面,vue就會對這個屬性進行監視,監視到數據不是完全掛載到數據屬性上的,就無法完成響應操作)
在vue中的源碼中會生成 Object.defineProperty(this, 'shopCart', { set:function(){ //判斷shopCart元素是否有屬性 })
解決方法:如果數據不完整掛載的情況在要添加屬性,就需要手動通知vue完成響應式,==》雙向數據綁定
created(){ let goodsList = GoodsTool.getGoodsList();//{"88":5,"99":4} 第一個數商品id 第二個是商品數量 let ids = Object.key(goodsList).join(',');//Object.key()獲取key值 [88,99] if(ids){ this.$axios.get(`goods/getshopcarlist${ids}`) .then(res=>{ this.shopCart=res.data.message;//返回的是一個數組 //給數組元素添加屬性 for(var i=0; i<this.shopCart.length;i++){ let shop=this.shopCart[i];//獲取到當前的對象 let num = goodsList[shop.id];//根據當前對象的id查找到對應的購物車數量 if(num){ shop.num = num; this.$set(shop, 'num', num);//自己給這個數據進行雙向數據綁定 this.$set(shop,'isSelected',true); } } }) }
三、總結
踩坑一:自己收動添加的屬性,需要用$set()給這個屬性綁定
踩坑二:vue 中存在一種機制會將shopCart(也就是你請求的數據進行監視)屬性進行監視,完成響應式(因為后面的num是我們自己加進去的,沒有掛載到數據屬性里面,vue就會對這個屬性進行監視,監視到數據不是完全掛載到數據屬性上的,就無法完成響應操作)