<!--規格產品的彈出層 s--> <section> <!--點擊選規格後彈出的遮罩層--> <transition name="fade"> <div class="specs_cover" @click="showChooseList" v-if="showSpecs"></div> </transition> <!--規格產品的彈出層 e--> <!--展開層 s--> <transition name="fadeBounce"> <div class="specs_list" v-if="showSpecs"> <!--header s--> <header class="specs_list_header"> <!--標題(當前已選擇規格商品的名字)--> </header> <!--繪製關閉規格彈出層的叉號 --> <svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" version="1.1" class="specs_cancel" @click="showChooseList"> <line x1="0" y1="0" x2="16" y2="16" stroke="#666" stroke-width="1.2"/> <line x1="0" y1="16" x2="16" y2="0" stroke="#666" stroke-width="1.2"/> </svg> <!--header e--> <!--規格詳情 s--> <section class="specs_details"> <!--顯示的文字爲"規格"--> <h5 class="specs_details_title"> {{choosedFoods.specifications[0].name}} </h5> <!--規格list s--> <ul> <!--specsIndex當前選中規格的索引值--> <li :class="{specs_activity: itemIndex == specsIndex}" v-for="(item,itemIndex) in choosedFoods.specifications[0].values" @click="chooseSpecs(itemIndex)"> {{item}} </li> </ul> <!--規格list e--> </section> <!--footer顯示價格和加入購物車--> <footer> <div class="specs_price"> <span>¥</span> <!--specsIndex:當前所選規格的下標對應的index--> <span>{{choosedFoods.specfoods[specsIndex].price}}</span> </div> <!--加入購物車,點擊的時候,執行addSpecs,傳入參數: category_id-食品分類id item_id-食品id food_id-食品規格id name-食品名字 price-食品價格 specs-食品規格 --> <div class="specs_addto_cart" @click="addSpecs( choosedFoods.category_id, choosedFoods.item_id, choosedFoods.specfoods[specsIndex].food_id, choosedFoods.specfoods[specsIndex].name, choosedFoods.specfoods[specsIndex].price, choosedFoods.specifications[0].values[specsIndex], choosedFoods.specfoods[specsIndex].packing_fee, choosedFoods.specfoods[specsIndex].sku_id, choosedFoods.specfoods[specsIndex].stock)"> 加入購物車 </div> </footer> <!--規格詳情 e--> </div> </transition> <!--展開層 e--> </section>
說明:
showSpecs:控制顯示上商品規格的彈出層,初始彈出層不顯示,showSpecs值爲false
showChooseList:點擊時經過改變showSpecs的值,來改變規格彈出層的顯示和隱藏
choosedFoods和foods的值相同,其數據結構以下:
規格list(循環展現):
chooseSpecs:該方法用於記錄當前所選規格的索引值vue
不可刪除,點擊減號會出現提示語,提示信息以下:git
<transition name="fade"> <p class="show_delete_tip" v-if="showDeleteTip"> 多規格商品只能去購物車刪除哦 </p> </transition>
說明:
showDeleteTip:多規格商品點擊減按鈕。彈出提示框。showDeleteTip的初始值爲falsegithub
<!--showMoveDot的初始值爲[],點擊+號以後,值爲[true,true]--> <transition appear @after-appear="afterEnter" @before-appear="beforeEnter" v-for="(item,index) in showMoveDot" :key="index"> <!--值爲true以後會顯示小球--> <span class="move_dot" v-if="item"> <!--繪製小球--> <svg class="move_liner"> <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#cart-add"></use> </svg> </span> </transition>
##### 說明
(1)加減按鈕:
listenInCart:監聽圓點是否進入購物車
showChooseList:是否顯示規格列表
showReduceTip:是否顯示"沒法減去規格"商品的提示語
showMoveDotFun:顯示下落小球
(2)totalNum:購物車中總共的商品數量
shopDetailData:商鋪詳情數據
經過web
this.shopDetailData = await shopDetails( this.shopId, this.latitude, this.longitude );
方法拿到,其數據結構以下:
(3)foods:
來源於menuList其中的某一項,其數據結構以下:
(4)clearCart:觸發,點擊購物車商品列表的"清空"
(5)toggleCartList:觸發,點擊購物車圖標,展開已加入購物車中的商品列表
(6)menuList食品列表:
經過
this.menuList = await foodMenu(this.shopId);
方法得到,其數據結構以下:
(7)Object.keys,返回器枚舉自身屬性的對象,
返回值一個表示給定對象的全部可枚舉屬性的字符串數組
處理對象:
處理字符串:
處理數組:
(8)foodItem的結構:
來源於initCategoryNum方法。該方法的做用在於在初始化、點擊+/-商品時。獲取加入購物車中的商品數量。
(細節部分不是很明白[○・`Д´・ ○]理解仍是不是很深刻)數組
export default{ data(){ //geohash位置信息 geohash: "", //購物車商品列表 cartFoodList:[], //商鋪詳情數據 shopDetailData:null, //總價格 totalPrice:0, //商店id值 shopId: null, //當前選中的食品數據 choosedFoods: null, //控制顯示食品規格 showSpecs:false, //當前選中的規格索引值 specsIndex: 0, //多規格商品點擊減按鈕。彈出提示框,初始值爲false,也就是默認不彈出 showDeleteTip:false, //顯示購物車商品列表(初始值爲false,不顯示,有加入購物車的商品時,點擊購物車圖標,來控制其顯示仍是隱藏) showCartList:false, //已加入購物車的商品列表 cartFoodList: [], //控制下落的小圓點的顯示隱藏 showMoveDot: [], //購物車下落圓球是否抵達指定位置 receiveInCart:false, //商品右上角已加入購物車的數量 categoryNum:[], //食品列表,初始值爲[] menuList:[] }, computed:{ ...mapState(["latitude", "longitude", "cartList"]), //購物車中商品總數量 totalNum:function(){ //初始狀態下cartFoodList的值爲[],totalNum的值爲0 let num=0; this.cartFoodList.forEach(item=>{ num+=item.num; }); return num; }, //minimumOrderAmount還差多少元起送 minimumOrderAmount:function(){ //拿到了shopDetailData以後執行 if(this.shopDetailData){ //還差多少元起送=最低起送價-總價 return this.shopDetailData.float_minimum_order_amount - this.totalPrice; } else{ return null; } }, //當前商鋪購物信息 shopCart:function(){ return {...this.cartList[this.shopId]} } }, created(){ //座標 this.geohash=this.$route.query.geohash; //商鋪id this.shopId=this.$route.query.id; this.INIT_BUYCART(); }, methods:{ ...mapMutations([ //加入購物車的方法 'ADD_CART', //移出購物車的方法 'REDUCE_CART', //初始化購物車 'INIT_BUYCART', //清空購物車 'CLEAR_CART', ]), ... //點擊"選規格"的時候執行-顯示規格列表 showChooseList(foods){ if(foods){ //choosedFoods已選中的食品數據就等於當前點擊項,所在item的list this.choosedFoods=foods; }, //規格彈出層的"顯示"/"隱藏"切換 this.showSpecs=!this.showSpecs; //當前選中的規格索引值 //重置當前所選中規格的索引值 this.specsIndex=0; }, //控制顯示沒法減去規格商品的提示語 showReduceTip(){ this.showDeleteTip=true; clearTimeout(this.timer); this.timer=setTimeout(()=>{ //3秒以後清空定製器 clearTimeout(this.timer); //將提示語進行隱藏 this.showDeleteTip=false; },3000); }, //記錄當前所選規格的索引值,(目的)在於給當前所選項添加active狀態的class chooseSpecs(index){ this.specsIndex=index; }, /*加入購物車:傳入參數 category_id-食品分類id item_id-食品id food_id-食品規格id name-食品名字 price-食品價格 specs-食品規格 */ addToCart(category_id, item_id, food_id, name, price, specs){ //this.ADD_CART方法在mutations.js中定義 this.ADD_CART({ //店鋪id shopid:this.shopId, //食品分類id category_id, //食品id item_id, //食品規格id food_id, //食品名字 name, //食品價格 price, //食品規格 specs }); }, //移出購物車: removeOutCart(category_id, item_id, food_id, name, price, specs){ this.REDUCE_CART({ //店鋪id shopid:this.shopId, //食品分類id category_id, //食品id item_id, //食品規格id food_id, //食品名字 name, //食品價格 price, //食品規格 specs }); }, //多規格商品加入購物車 /*傳入參數 category_id-食品分類id item_id-食品id food_id-食品規格id name-食品名字 price-食品價格 specs-食品規格 packing_fee:打包費 sku_id:庫存id stock:庫存 */ addSpecs(category_id, item_id, food_id, name, price, specs, packing_fee, sku_id, stock){ this.ADD_CART({shopid:this.shopId, category_id, item_id, food_id, name, price, specs, packing_fee, sku_id, stock }); //規格商品加入購物車以後,隱藏規格的彈出層 this.showChooseList(); }, //清空購物車 clearCart(){ //點擊了 this.CLEAR_CART(this.shopId); //隱藏已展現的購物車列表 this.toggleCartList(); }, //控制已加入購物車的商品列表的顯示和隱藏 toggleCartList(){ //cartFoodList已加入購物車的商品列表,初始值爲[] //showCartList的值控制是否顯示列表 this.cartFoodList.length ? this.showCartList=!this.showCartList:true }, //顯示下落小球 showMoveDotFun(showMoveDot, elLeft, elBottom){ //點擊加號以後,this.showMoveDot的值從[],變成true,下落的小圓球顯示 this.showMoveDot=[...showMoveDot,...showMoveDot]; //應該是初始狀態小球的位置吧 this.elLeft=elLeft; this.elBottom=elBottom; }, //動畫初次渲染前 beforeEnter(el){ //初次渲染的時候,肯定小球的位置 // 設置transform值 el.style.transform = `translate3d(0,${37 + this.elBottom - this.windowHeight}px,0)`; el.children[0].style.transform = `translate3d(${this.elLeft - 30}px,0,0)`; //設置不透明度 el.children[0].style.opacity = 0; }, //動畫渲染後(讓小球從當前位置移動到底部) afterEnter(el){ el.style.transform=`translate3d(0,0,0)`; el.children[0].style.transform=`translate3d(0,0,0)`; el.style.transition = 'transform .55s cubic-bezier(0.3, -0.25, 0.7, -0.15)'; el.children[0].style.transition = 'transform .55s linear'; //到達底部以後把下落的小球隱藏起來 this.showMoveDot = this.showMoveDot.map(item => false); //設置不透明度 el.children[0].style.opacity = 1; //判斷是否已經到達底部 el.children[0].addEventListener('transitionend',()=>{ this.listenInCart(); }); el.children[0].addEventListener('webkitAnimationEnd',()=>{ this.listenInCart(); }); }, //監聽小圓球是否進入購物車 listenInCart(){ //receiveInCart的初始值爲false,用來判斷下落的小圓球是否抵達指定位置 if(!receiveInCar){ this.receiveInCart=true; this.$refs.cartContainer.addEventListener('animationend',()=>{ this.receiveInCart=false; }); this.$refs.cartContainer.addEventListener('webkitAnimationEnd',()=>{ this.receiveInCart = false; }); } }, /*初始化和shopCart變化時,從新湖區購物車改變過的數據, 賦值 categoryNum,totalPrice,cartFoodList,整個數據流是自上而下的形式, 商品右上角已加入購物車的數量categoryNum[] totalPrice:總價格,初始值是0 cartFoodList:已加入購物車的商品列表初始值是[] */ initCategoryNum(){ //一個空數組 let newArr=[]; //初始狀態下,已加入購物車的商品數量 let cartFoodNum=0; //已加入購物車的商品總價,初始值爲0 this.totalPrice=0; //已加入購物車的商品列表 this.cartFoodList=[]; this.menuList.forEach((item,index)=>{ if(this.shopCart&&this.shopCart[item.foods[0].category_id]){ let num=0; Object.keys(this.shopCart[item.foods[0].category_id]).forEach(itemid=>{ Object.keys(this.shopCart[item.foods[0].category_id][itemid]).forEach(foodid=>{ let foodItem = this.shopCart[item.foods[0].category_id][itemid][foodid]; num+=foodItem.num; //item.type==1能夠說明什麼嗎? if(item.type==1){ this.totalPrice+=foodItem.num*foodItem.price; if(foodItem.num>0){ this.cartFoodList[cartFoodNum] = {}; this.cartFoodList[cartFoodNum].category_id = item.foods[0].category_id; this.cartFoodList[cartFoodNum].item_id = itemid; this.cartFoodList[cartFoodNum].food_id = foodid; this.cartFoodList[cartFoodNum].num = foodItem.num; this.cartFoodList[cartFoodNum].price = foodItem.price; this.cartFoodList[cartFoodNum].name = foodItem.name; this.cartFoodList[cartFoodNum].specs = foodItem.specs; cartFoodNum ++; } } }); }) //已加入購物車的商品數量 newArr[index] = num; } else{ newArr[index] = 0; } this.totalPrice = this.totalPrice.toFixed(2); this.categoryNum = [...newArr]; }) }, ... }, watch:{ //showLoading變化時說明組件已經獲取初始化數據,在下一幀nextTick進行後續操做 showLoading:function(value){ if(!value){ this.$nextTick(()=>{ //獲取食品列表的高度 this.getFoodListHeight(); //初始化和shopCart變化時,從新獲取購物車改變過的數據 this.initCategoryNum(); }); } }, //當前商店購物信息 shopCart:function(value){ this.initCategoryNum(); }, //購物車列表發生變化,沒有商鋪時隱藏 //cartFoodList:購物車商品列表 cartFoodList:function(value){ if(!value.length){ this.showCartList = false; } } } }
mutations.js中定義的方法:數據結構
//引入常量 import { SAVE_GEOHASH, RECORD_ADDRESS, ADD_CART, REDUCE_CART, CLEAR_CART, BUY_CART, SAVE_SHOPID, INIT_BUYCART, RECORD_SHOPDETAIL } from './mutation-types.js' import { setStore, getStore } from '../config/mUtils'; export default { //保存geohash [SAVE_GEOHASH](state, geohash) { state.geohash = geohash; }, //記錄當前具體的位置信息 [RECORD_ADDRESS](state, { latitude, longitude }) { state.latitude = latitude; state.longitude = longitude; }, //加入購物車 [ADD_CART](state, { shopid, category_id, item_id, food_id, name, price, specs, packing_fee, sku_id, stock }) { let cart = state.cartList; let shop = cart[shopid] = (cart[shopid] || {}); let category = shop[category_id] = (shop[category_id] || {}); let item = category[item_id] = (category[item_id] || {}); if (item[food_id]) { item[food_id]['num']++; } else { item[food_id] = { "num" : 1, "id" : food_id, "name" : name, "price" : price, "specs" : specs, "packing_fee" : packing_fee, "sku_id" : sku_id, "stock" : stock }; } state.cartList = {...cart}; //存入localStorage setStore('buyCart', state.cartList); }, //移出購物車 [REDUCE_CART](state, { shopid, category_id, item_id, food_id, name, price, specs, }) { let cart = state.cartList; let shop = (cart[shopid] || {}); let category = (shop[category_id] || {}); let item = (category[item_id] || {}); if (item && item[food_id]) { if (item[food_id]['num'] > 0) { item[food_id]['num']--; state.cartList = {...cart}; //存入localStorage setStore('buyCart', state.cartList); } else { //商品數量爲0,則清空當前商品的信息 item[food_id] = null; } } }, //清空當前商品的購物車信息 [CLEAR_CART](state,shopid){ state.cartList[shopid] = null; state.cartList = {...state.cartList}; setStore('buyCart', state.cartList); }, //保存商鋪id [SAVE_SHOPID](state, shopid) { state.shopid = shopid; }, //初始化購物車 [INIT_BUYCART](state){ let initCart=getStore('buyCart'); if(initCart){ state.cartList=JSON.parse(initCart); } }, //RECORD_SHOPDETAIL [RECORD_SHOPDETAIL](state,detail){ state.shopDetail=detail; } }
參照項目地址:地址app