vue 全家桶(七)vuex 状态管理(实现购物车)

Vuex 解决了多个视图依赖于同一状态来自不同视图的行为需要变更同一状态的问题,将开发者的精力集中于数据的更新而不是数据在组件之间的传递上。

本文以购物车为例,对概念没有过多阐述,建议先浏览官网:https://vuex.vuejs.org/

一. 预期效果

   - 【页面】商品列表组件、购物车列表组件、商品结算组件

   - 【功能】将商品加入购物车,更新购物车列表

   - 【功能】增减商品时,库存、总数、总价变化

  vue 全家桶(七)vuex 状态管理(实现购物车)_第1张图片

二. 具体实现

  1.文件结构

store
    ├── index.js             # 导出 store 的地方
    ├── state.js             # 根级别的 state
    ├── getters.js           # 二次包装state数据
    ├── actions.js           # 根级别的 action
    ├── mutations.js         # 根级别的 mutation
    ├── mutation-types.js    # 所有 mutation 的常量映射表

2.安装

npm install vuex --save

3.在src目录下新建store/index.js,代码如下:

import Vue from 'vue';
import Vuex from 'vuex';

import actions from '@/store/actions.js';
import getters from '@/store/getters.js';
import mutations from '@/store/mutations.js';
import state from '@/store/states.js';

Vue.use(Vuex);


export default new Vuex.Store({
  state,
  mutations,
  getters,
  actions,
})

4.在main.js文件中引入

import router from './router'
import store from './store/index'

new Vue({
  el: '#app',
  router,
  util,
  store,
  components: {App},
  template: ''
})

   5.页面搭建及组件实现(注:这里的组件都是全局注册的,可参考:https://blog.csdn.net/try_try_try/article/details/85264175)

   - 数据准备

goodsData: [
          { 'id': 1, 'url':imgTmp, 'name': "美的洗碗机", 'price': 2000,'inventory':5,'num':1 },
          { 'id': 2, 'url':imgTmp, 'name': "美的豆浆机", 'price': 1000,'inventory':100,'num':1 },
          { 'id': 3, 'url':imgTmp, 'name': "美的微波炉", 'price': 1500,'inventory':80,'num':1 }
        ]

  - 商品列表项组件(goodsItem)






  - 购物车列表组件(shopCartList )






 - 主页面,到目前为止我们就可以看到开篇的页面效果了






6.下面终于到vuex登场啦,先来看看具体有哪些交互以及实现方式

vue 全家桶(七)vuex 状态管理(实现购物车)_第2张图片

 - 由图我们可以看到购物车的列表数据是我们三个组件操作的数据源,那么我们来看看store/states.js 中的代码实现

//用于数据的存储,是store中的唯一数据源

const state = {
  shopList:[]//购物车列表
};

export default state;

7.加入购物车功能

当点击加入购物车时,即需要修改store的state,我们知道更改 Vuex 的 store 中的状态的唯一方法是提交 mutation,由于mutation 必须同步执行,我们一般通过 action来提交mutation,下面我们来看看store/actions.js中的代码实现

//actions 类似于mutation,用于提交mutation来改变状态,而不直接变更状态,可以包含任意异步操作

import mutationTypes from './mutationTypes.js'

export default{
  addGoods({commit},params){ //params对应mutation对象中参数info
    commit(mutationTypes.ADD_GOODS,params);
  }
}

store/mutationTypes.js

// 所有 mutation 的类型

const mutationTypes = {
  ADD_GOODS: 'addGoods'
};

export default mutationTypes;

store/mutations.js

//mutations,改变state数据的唯一途径,且不能用于处理异步事件

import mutationTypes from './mutationTypes.js'

const mutations = {
    [mutationTypes.ADD_GOODS](state, info) { //接受actions传过来的参数
      let isOwn = state.shopList.some(function(item){
        if(item.id == info.id){
          if(item.inventory!=0){
            item.num++;
            item.inventory--;
          }
          return true;
        }else{
          return false;
        }
      });

      if(!isOwn){
        state.shopList.push({id:info.id,name:info.name,price:info.price,inventory:info.inventory-1,num:1});
      }
    }
  };

export default mutations;

  到此整个流程就很清晰了,actions从用户那里拿到数据后,提交给mutations,由mutation做数据的修改。

  接下来就是在添加商品的组件中(goodsItem)引入mapActions并使用它:

vue 全家桶(七)vuex 状态管理(实现购物车)_第3张图片

现在我们就实现了将商品加入购物车的功能,增加数量(addNum)、减少数量(reduceNum)、移除商品(deleteGoods)、清空购物车(clearShopCart)与加入购物车实现方法一致。完整的actions、mutations如下:

import mutationTypes from './mutationTypes.js'

export default{
  addGoods({commit},params){ //params对应mutation对象中参数info
    commit(mutationTypes.ADD_GOODS,params);
  },
  addNum({commit},params){
    console.log("addNum");
    commit(mutationTypes.ADD_NUM,params);
  },
  reduceNum({commit},params){
    commit(mutationTypes.REDUCE_NUM,params);
  },
  deleteGoods({commit},params){
    commit(mutationTypes.DELETE_GOODS,params);
  },
  clearShopCart({commit}){
    commit(mutationTypes.CLEAR_SHOP_CART);
  }
}

 

import mutationTypes from './mutationTypes.js'

const mutations = {
    [mutationTypes.ADD_GOODS](state, info) {
      let isOwn = state.shopList.some(function(item){
        if(item.id == info.id){
          if(item.inventory!=0){
            item.num++;
            item.inventory--;
          }
          return true;
        }else{
          return false;
        }
      });

      if(!isOwn){
        state.shopList.push({id:info.id,name:info.name,price:info.price,inventory:info.inventory-1,num:1});
      }
    },
    [mutationTypes.ADD_NUM](state, index) {
      if(state.shopList[index].inventory!=0){
        state.shopList[index].num++;
        state.shopList[index].inventory--;
      }
    },
    [mutationTypes.REDUCE_NUM](state, index) {
      if(state.shopList[index].num == 0){
        state.shopList.splice(index,1);
      }else{
        state.shopList[index].num--;
        state.shopList[index].inventory++;
      }
    },
    [mutationTypes.DELETE_GOODS](state, index) {
      state.shopList.splice(index,1);
    },
    [mutationTypes.CLEAR_SHOP_CART](state) {
      state.shopList = [];
    },
  }
  ;
export default mutations;

8.结算组件中(shopCartAccount)的数量以及金额统计,现在就到我们的store/getters.js登场了

//基于state数据的二次包装,常用于数据的筛选和多个数据的相关性计算

import state from './states.js';

export default{
  totalPrice(){
    let totalPrice = 0;   // 计算总价
    for(let i =0;i

 结算组件中的使用:

vue 全家桶(七)vuex 状态管理(实现购物车)_第4张图片

至此,整个demo就完成了,vuex的简单使用也算是分享完了,感谢您看完了这篇长文,有哪里不明白的或不对的,留言下,咱们可以一起讨论、共同学习!

 

你可能感兴趣的:(vue,vue)