说明
【Vue 开发实战】学习笔记。
核心概念
State一this.$store.state.xxx 取值——mapState 取值
Getter 一this.$store.getters.xxx 取值——mapGetters 取值
Mutation 一this.$store.commit( "xxx" )赋值——mapMutations 赋值
Action 一 this.$store.dispatch( "xxx" )赋值——mapActions 赋值
Module
使用常量替代Mutation事件类型
Module
- 开启命名空间
namespaced: true
- 嵌套模块不要过深,尽量扁平化
- 灵活应用 createNamespacedHelpers
当使用 mapState、mapGetters、mapActions 和 mapMutations 这些函数来绑定带命名空间的模块时,写起来可能比较繁琐:
computed: { ...mapState({ a: state => state.some.nested.module.a, b: state => state.some.nested.module.b }), ...mapGetters([ 'some/nested/module/someGetter', // -> this['some/nested/module/someGetter'] 'some/nested/module/someOtherGetter', // -> this['some/nested/module/someOtherGetter'] ]) }, methods: { ...mapActions([ 'some/nested/module/foo', // -> this['some/nested/module/foo']() 'some/nested/module/bar' // -> this['some/nested/module/bar']() ]) }
可以通过使用 createNamespacedHelpers
创建基于某个命名空间辅助函数。它返回一个对象,对象里有新的绑定在给定命名空间值上的组件绑定辅助函数:
import { createNamespacedHelpers } from 'vuex' const { mapState, mapActions } = createNamespacedHelpers('some/nested/module') export default { computed: { // 在 `some/nested/module` 中查找 ...mapState({ a: state => state.a, b: state => state.b }) }, methods: { // 在 `some/nested/module` 中查找 ...mapActions([ 'foo', 'bar' ]) } }
实践:购物车例子
完整例子请查看:https://github.com/kaimo313/vue-development-practice/tree/master/vuex-demo2
部分代码:
vuex-demo2\src\store\mutation-types.js
export const CART = { PUSH_PRODUCT_TO_CART: 'pushProductToCart', INCREMENT_ITEM_QUANTITY: 'incrementItemQuantity', SET_CART_ITEMS: 'setCartItems', SET_CHECKOUT_STATUS: 'setCheckoutStatus', } export const PRODUCTS = { SET_PRODUCTS:'setProducts', DECREMENT_PRODUCT_INVENTORY: 'decrementProductInventory' }
vuex-demo2\src\store\index.js
import Vue from 'vue' import Vuex from 'vuex' import cart from './modules/cart' import products from './modules/products' Vue.use(Vuex) export default new Vuex.Store({ state: { userInfo: { email: "xxxxxx@qq.com" } }, modules: { cart, products }, })
vuex-demo2\src\store\modules\cart.js
import shop from '../../api/shop' import { CART, PRODUCTS } from '../mutation-types' // initial state // shape: [{ id, quantity }] const state = { items: [], checkoutStatus: null } // getters const getters = { cartProducts: (state, getters, rootState) => { return state.items.map(({ id, quantity }) => { const product = rootState.products.all.find(product => product.id === id) return { title: product.title, price: product.price, quantity } }) }, cartTotalPrice: (state, getters) => { return getters.cartProducts.reduce((total, product) => { return total + product.price * product.quantity }, 0) } } // actions const actions = { checkout ({ commit, state }, products) { const savedCartItems = [...state.items] commit(CART.SET_CHECKOUT_STATUS, null) // empty cart commit(CART.SET_CART_ITEMS, { items: [] }) shop.buyProducts( products, () => commit(CART.SET_CHECKOUT_STATUS, 'successful'), () => { commit(CART.SET_CHECKOUT_STATUS, 'failed') // rollback to the cart saved before sending the request commit(CART.SET_CART_ITEMS, { items: savedCartItems }) } ) }, addProductToCart ({ state, commit }, {product, number}) { commit(CART.SET_CHECKOUT_STATUS, null) if (product.inventory > 0) { const cartItem = state.items.find(item => item.id === product.id) if (!cartItem) { commit(CART.PUSH_PRODUCT_TO_CART, { id: product.id, number }) } else { commit(CART.INCREMENT_ITEM_QUANTITY, {cartItem, number}) } // remove number item from stock commit(`products/${PRODUCTS.DECREMENT_PRODUCT_INVENTORY}`, { id: product.id, number }, { root: true }) } } } // mutations const mutations = { [CART.PUSH_PRODUCT_TO_CART] (state, { id, number }) { state.items.push({ id, quantity: number }) }, [CART.INCREMENT_ITEM_QUANTITY] (state, { cartItem: {id}, number }) { const cartItem = state.items.find(item => item.id === id) cartItem.quantity += number }, [CART.SET_CART_ITEMS] (state, { items }) { state.items = items }, [CART.SET_CHECKOUT_STATUS] (state, status) { state.checkoutStatus = status } } export default { namespaced: true, state, getters, actions, mutations }
vuex-demo2\src\components\ShoppingCart.vue
<template> <div class="cart"> <h2>清单</h2> <p v-show="!products.length"><i>请添加产品到购物车</i></p> <ul> <li v-for="product in products" :key="product.id"> {{ product.title }} - {{ product.price }} x {{ product.quantity }} </li> </ul> <p>合计: {{ total }}</p> <p><button :disabled="!products.length" @click="checkout(products)">提交</button></p> <p v-show="checkoutStatus">提交 {{ checkoutStatus }}.</p> </div> </template> <script> import { mapGetters, mapState } from 'vuex' export default { computed: { ...mapState({ checkoutStatus: state => state.cart.checkoutStatus }), ...mapGetters('cart', { products: 'cartProducts', total: 'cartTotalPrice' }), // ...mapGetters({ // products: 'cart/cartProducts', // total: 'cart/cartTotalPrice' // }) }, // computed: { // checkoutStatus(){ // return this.$store.state.cart.checkoutStatus // }, // products() { // return this.$store.getters['cart/cartProducts'] // }, // total() { // return this.$store.getters['cart/cartTotalPrice'] // } // }, methods: { checkout (products) { this.$store.dispatch('cart/checkout', products) } }, } </script>