点击“加入购物车”后,商品信息便被保存在product对象中了,而要想把product对象分享给购物车Cart组件,最好的办法就是将它加入到全局的vuex中。
我们创建一个store文件夹,将index.js文件作为状态管理模块的入口,代码如下:
import Vue from 'vue' import Vuex from 'vuex' import mutations from './mutations' import actions from './actions' import getters from './getters'; Vue.use(Vuex) const state = { cartList: [] } const store = new Vuex.Store({ state, mutations, actions, getters }) export default store
注意到mutations、actions和getters都被抽离出去了,state虽然没有抽离,但也单独进行了定义。而且在实例化store对象时,不是直接调用Vuex构造函数,而是调用其Vuex.Store方法。
在Detail组件中的addToCart方法中,最后一行为:
this.$store.dispatch('addCart',product)
这条语句的功能为,将product作为参数,调用actions中的addCart方法。而addCart方法定义如下:
addCart(context, payload){ let oldProduct = context.state.cartList.find( item => item.iid === payload.iid) if (oldProduct) { // 如果是已有商品,则数量加一 context.commit(ADD_COUNTER, oldProduct) }else{ // 如果是新商品,则添加一个新item,且其数量初始化为1 payload.count = 1 context.commit(ADD_TO_CART, payload) } }
基本逻辑是:首先判断当前购物车列表中有没有新加入的这件商品,如果有,则数量加一;如果没有,则作为新商品加入,数量初始化为1。
那为什么这个功能不直接在mutations中实现呢?原因是我们希望mutations中的方法功能都比较单一,而addCart中存在一个判断逻辑,两种判断结果对应两种截然不同的操作,所以我们需要将其放在actions中。此外,由于state中的数据只能在mutations中修改,所以具体的操作还是需要在mutaions中来完成——context.commit的功能就是将oldProduct或payload作为参数,调用mutaions中的ADD_COUNT方法或ADD_TO_CART方法。(这里的形参名context、payload都是约定俗成的。)
[ADD_COUNTER](state, payload){ payload.count++ }, [ADD_TO_CART](state, payload){ state.cartList.push(payload) }
事实上,mutations中的方法名通常为定义好的常量,所以在store文件夹中还要有一个专门定义常量的文件mutations-types.js。
export const ADD_COUNTER = 'add_counter'
export const ADD_TO_CART = 'add_to_cart'