vue2-elm學習記錄(Day12)

效果實現(續):

(1)規格商品
規格商品,點擊後出現:

image.png

<!--規格產品的彈出層 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的值相同,其數據結構以下:
image.png
規格list(循環展現):
image.png
chooseSpecs:該方法用於記錄當前所選規格的索引值vue

選擇規格商品以後:

image.png
不可刪除,點擊減號會出現提示語,提示信息以下:git

<transition name="fade">
    <p class="show_delete_tip" v-if="showDeleteTip">
        多規格商品只能去購物車刪除哦
    </p>
</transition>

說明:
showDeleteTip:多規格商品點擊減按鈕。彈出提示框。showDeleteTip的初始值爲falsegithub

(2)下落小球
<!--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)加減按鈕:
image.png
listenInCart:監聽圓點是否進入購物車
showChooseList:是否顯示規格列表
showReduceTip:是否顯示"沒法減去規格"商品的提示語
showMoveDotFun:顯示下落小球
(2)totalNum:購物車中總共的商品數量
shopDetailData:商鋪詳情數據
經過web

this.shopDetailData = await shopDetails(
  this.shopId,
  this.latitude,
  this.longitude
);

方法拿到,其數據結構以下:
image.png
(3)foods:
來源於menuList其中的某一項,其數據結構以下:
image.png
(4)clearCart:觸發,點擊購物車商品列表的"清空"
image.png
(5)toggleCartList:觸發,點擊購物車圖標,展開已加入購物車中的商品列表
image.png
(6)menuList食品列表:
經過
this.menuList = await foodMenu(this.shopId);
方法得到,其數據結構以下:
image.png
image.png
image.png
(7)Object.keys,返回器枚舉自身屬性的對象,
返回值一個表示給定對象的全部可枚舉屬性的字符串數組
處理對象:
image.png
處理字符串:
image.png
處理數組:
image.png
(8)foodItem的結構:
image.png
來源於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

相關文章
相關標籤/搜索