天天看點

底部購物車(美團外賣效果)

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>

           

效果圖:

底部購物車(美團外賣效果)