vue2-elm学习记录(Day10)

实现三:商品和评价切换(续)

food-detail-list的内容:
image.pngvue

...
<section class="menu_detail_list" v-for="(foods,foodindex) in item.foods" :key="foodindex">
    <!--点击跳转到食物详情页面,须要传入的参数:
        image_path:图片路径,
        description:食物描述
        month_sales:月销量
        name:食物名字
        ratting:评分,
        rating_count:销售量,
        satisfy_rate:满意度,
        foods:食物,
        shopId:店铺id-->
        <router-link class="menu_detail_link" :to="{
        path:'shop/foodDetail',query:{image_path:foods.image_path,
        description:foods.description,
        month_sales:foods.month_sales,
        name:foods.name,
        rating:foods.rating,
        rating_count:foods.rating_count,
        satisfy_rate:foods.satisfy.rate,
        foods.shopId}
        }" tag="div">
            <!--图片 s-->
            <section class="menu_food_img">
                <img :src="imgBaseUrl+foods.image_path">
            </section>
            <!--图片 e-->
            <!--描述信息 s-->
            <section class="menu_food_description">
                <h3 class="food_description_head">
                    <!--标题-->
                    <strong class="description_foodname">
                        {{foods.name}}
                    </strong>
                    <!--是不是新品 s-->
                    <ul class="attributes_ul" v-if="foods.attributes.length">
                        <li v-if="attribute" v-for="(attribute,foodIndex) in foods.attributes"
                         :key="foodindex" :style="{color:'#'+attribute.icon_color,
                          borderColor:'#'+attribute.icon_color}"
                          :class="{attribute_new:attribute.icon_name=='新'}">
                            <!--attribute.icon_name=='新'的时候,显示name值,并未其添加样式-->
                            <p :style="{color:attribute.icon_name=='新'?'#fff':'#'+attribute.icon_color}">
                               {{attribute.icon_name=='新'?'新品':attribute.icon_name}}
                            </p>
                        </li>
                    </ul>
                    <!--是不是新品 e-->
                </h3>
                <!--描述信息-->
                <p class="food_description_content">
                    {{foods.description}}
                </p>
                <!--销量和满意度-->
                <p class="food_description_sale_rating">
                    <span>月售{{foods.month_sales}}份</span>
                    <span>好评率{{foods.satisfy_rate}}%</span>
                </p>
                <!--foods.activity是已售的意思吗-->
                <p v-if="foods.activity" class="food_activity">
                    <span :style="{color:'#'+foods.activity.image_text_color,
                     borderColor:'#'+foods.activity.icon_color}">
                        {{foods.activity.image_text}}
                    </span>
                </p>
            </section>
            <!--描述信息 e-->
        </router-link>
        <!--价格 s-->
        <footer class="menu_detail_footer">
            <section class="food_price">
                <span>¥</span>
                <span>{{foods.specfoods[0].price}}</span>
                <span v-if="foods.specifications.length"></span>
            </section>
        </footer>
        <!--价格 e-->
</section>
...

说明:
foods的数据结构以下:
image.pnggit

功能(1):增长点击右侧"..."显示说明信息

image.png

...
<header class="menu_detail_header">
    ...
    <!--点击部分-->
    <span class="menu_detail_header_right" @click="showTitleDetail(index)"></span>
    <!--点击的时候控制TitleDetailIndex值进而控制列表的展现和隐藏-->
    <p class="description_tip" v-if="index==TitleDetailIndex">
        <span>{{item.name}}</span>
        {{item.description}}
    </p>
</header>
...

JS部分:github

export default{
        data(){
            return{
            ...
            //点击展现列表头部详情
            TitleDetailIndex:null
            
            }
        },
        //说明信息的隐藏和显示
        showTitleDetail(index){
            if(this.TitleDetailIndex==index){
                this.TitleDetailIndex=null;
            }
            else{
                this.TitleDetailIndex=index;
            }
        
        }
        
    }
功能(2):加购

若标识规格的参数specifications没有长度的时候显示+号,若标识规格的参数specifications有长度时显示"规格"。
image.png
须要用到Vuex。vuex

知识点:

(1)vuex的状态存储是响应式的,因此从store中读取状态最简单的方法就是经过computed计算属性。
每当state中的状态发生变化时,就会从新计算获取计算属性从而映射到View。
(2)当一个组件有多个状态的时候,会形成计算属性重复和代码冗余。为了解决这个问题,咱们可使用
mapState辅助函数帮助咱们生成计算属性:
(3)Mutations修改状态的值,vue视图是由数据驱动的,也就是说state里面的数据是动态变化的,而改变的
惟一方法就是mutation,通俗的理解,mutations里面装着一些改变数据方法的集合。每一个 mutation 都有一个字符串的事件类型 (type) 和 一个回调函数 (handler)。事件类型就是经过$store.commit()提交的事件。回调
函数就是咱们实际进行状态更改的地方,它做为store中的mutations对象的一个属性而存在。
(4)在组件中提交Mutations
首先引入mapMutations
import {mapState,mapMutations} from 'vuex'
添加methods属性,并加入mapMutations
eg:数组

...
methods:{
    //若是组件中事件的名称和mutations中方法的名称相同,能够传一个字符串数组
    ...mapMutations([
        'add'//映射this.add()为this.$store.commit('add')
    ])
}

(5)Actions:是异步修改状态。actions和mutations是相似的,不一样之处在于:数据结构

  • Action提交的是Mutation,不可以直接修改state中的状态,而Mutations是能够直接修改state中状态的;
  • Action是支持异步操做的,而Mutations只能是同步操做。
实现:

mutation-types.js中定义:异步

//加入购物车
export const ADD_CART = 'ADD_CART'
//移除购物车
export const REDUCE_CART = 'REDUCE_CART'
//清空购物车
export const CLEAR_CART='CLEAR_CART'
//保存商铺ID
export const SAVE_SHOPID = 'SAVE_SHOPID'

mutations.js中定义方法:svg

//引入常量
import {ADD_CART,REDUCE_CART,CLEAR_CART,SAVE_SHOPID} from './mutation-types.js'
import {setStore,getStore} from '../config/mUtils';
export default{
   //加入购物车
   [ADD_CART](state,{
        //店铺id
        shopid,
        //分类id
        categpry_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
            "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;
   }
}

store文件夹下的index.js:函数

const state={
    ...
    //加入购物车的商品列表
    cartList:{},
    //商铺id
    shopid:null,
    //购物车id
    cartId:null
}
export default new Vuex.Store({
    state,
    getters,
    actions,
    mutations
})

buyCart.vue:布局

<section class="cart_module">
    <!--显示+/-号的状况 s -->
    <section class="cart_button" v-if="!foods.specifications.length">
        <!--减号(有数字的时候显示)-->
        <transition name="showReduce">
            <span v-if="foodNum">
                <!--点击减号执行removeOutCart,removeOutCart的对应方法
                    在mutations.js中
                    须要传入的参数:
                    category_id(类别id)
                    item_id(项目id)
                    specfoods(特殊食品)的:
                    food_id(食品id),
                    name(食品的名字),
                    price(食品的价格),
                    packing_fee(食品包装费)
                    sku_id(库存id)
                    stock(存货)
                 -->
                <svg  @click="removeOutCart(
                      foods.category_id,
                      foods.item_id,
                      foods.specfoods[0].food_id,
                      foods.specfoods[0].name,
                      foods.specfoods[0].price,
                      '',
                      foods.specfoods[0].packing_fee,
                      foods.specfoods[0].sku_id,
                      foods.specfoods[0].stock)">
                    <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#cart-minus" />
                </svg>
            </span>
        </transition>
        <!--数字 foodNum来自于mutations.js中-->
        <transition name="fade">
            <span class="cart_num" v-if="foodNum">{{foodNum}}</span>
        </transition>
        <!--加号:点击+号执行addToCart方法,传入参数同上-->
        <svg class="add_icon"  @click="addToCart(
          foods.category_id,
          foods.item_id,
          foods.specfoods[0].food_id,
          foods.specfoods[0].name,
          foods.specfoods[0].price,
          '',
          foods.specfoods[0].packing_fee,
          foods.specfoods[0].sku_id,
          foods.specfoods[0].stock,
          $event)">
            <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#cart-add" />
        </svg>
    </section>
    <!--显示+/-号的状况 e-->
    <!--显示规格的状况  s-->
    <section class="choose_specification" v-else>
        <section class="choose_icon_container">
            <transition name="showReduce">
                <!--点击的时候执行showReduceTip方法-->
                <svg class="specs_reduce_icon" v-if="foodNum" @click="showReduceTip">
                   <use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#cart-minus" />
                </svg>
            </transition>
            <transition name="fade">
                <!--显示的数字,有点看不懂-->
                <span class="cart_num" v-if="foodNum">{{foodNum}}</span>
            </transition>
            <!--点击的时候显示规则选择框-->
            <span class="show_chooselist" @click="showChooseList(foods)">选规格</span>
        </section>
    </section>
    <!--显示规格的状况  e-->
</section>

JS部分

export default{
        data(){
            return{
                //控制下落的小圆点的显示和隐藏
                showMoveDot:[]
            }
        },
        mounted(){},
        computed:{
            //获取cartList,将this.cartList映射为this.$store.commit('add_cart')
            ...mapState(["cartList"]),
            //监听cartList变化,更新当前商铺的购物车信息shopCart,同时返回一个新的对象
            shopCart:function(){
                return Object.assign({},this.cartList[this.shopId]);
            },
            //添加的食品的个数
            foodNum:function(){
                 //类型id
                 let category_id = this.foods.category_id;
                 //项目id
                 let item_id = this.foods.item_id;
                 //这个地方判断的做用没搞懂,若它们都有值能表明什么呢
                 if(this.shopCart &&
        this.shopCart[category_id] &&
        this.shopCart[category_id][item_id]){
                      let num=0;
                      Object.values(this.shopCart[category_id][item_id]).forEach(
                        (item,index)=>{
                            num+item.num
                        }
                      );
                      return num
                        
                        
                  }
                  else{
                    return 0;
                  }
            }
            
        },
        props: ["foods", "shopId"],
        methods:{
          ...mapMutations(["ADD_CART", "REDUCE_CART"]),
          //移出购物车
          removeOutCart(category_id,
               item_id,
               food_id,
                name,
                price,
                specs,
                packing_fee,
                sku_id,
                stock){
                if(this.foodNum>0){
                    //调用REDUCE_CART方法
                    this.REDUCE_CART({
                      shopid: this.shopId,
                      category_id,
                      item_id,
                      food_id,
                      name,
                      price,
                      specs,
                      packing_fee,
                      sku_id,
                      stock
                    });
                 
                 }
          
            },
            //加入购物车
            addToCart(
            category_id,
            item_id,
            food_id,
            name,
            price,
            specs,
            packing_fee,
            sku_id,
            stock,
            event){
               this.ADD_CART({
                    shopid: this.shopId,
                    category_id,
                    item_id,
                    food_id,
                    name,
                    price,
                    specs,
                    packing_fee,
                    sku_id,
                    stock
               }); 
               let elLeft=event.target.getBoundingClientRect().left;
               let elBottom=event.target.getBoundingClientRect().bottom;
               this.showMoveDot.push(true);
               this.$emit("showMoveDot",this.showMoveDot,elLeft,elBottom);
            },
            //显示规格列表
            showChooseList(foodScroll){
                this.$emit("showChooseList",foodScroll);
            },
            //点击多规格商品的减按钮,弹出提示
            showReduceTip(){
                this.$emit("showReduceTip");
            }
        }
    }

shop.vue中引入buyCart.vue:

...
<section class="menu_right" ref="menuFoodList">
    <ul>
        <li v-for="(item,index) in menuList" :key="index">
            ...
            <footer class="menu_detail_footer">
                ...
                <!--showChooseList显示规格列表
                    showReduceTip:点击多规格商品的减按钮,弹出提示
                    showMoveDot:
                    传递过来的参数:this.$emit("showMoveDot",this.showMoveDot,elLeft,elBottom)
                -->
                <buy-cart :shopid="shopId" :foods="foods"
                      @moveInCart="listenInCart"
                      @showChooseList="showChooseList"
                      @showReduceTip="showReduceTip"
                      @showMoveDot="showMoveDotFun"
                  >
                    
                </buy-cart>
            </footer>
        </li>
    </ul>
</section>

到此为止,规格和加号的布局已完整。功能实现收其余部分的影响,暂时不作说明。
参照项目地址:地址

相关文章
相关标签/搜索