前言 上回咱們說了一下 vuex 的簡單使用,最後面的時候有說了,因爲使用單一狀態樹,應用的全部狀態會集中到一個比較大的對象。當應用變得很是複雜時,store 對象就有可能變得至關臃腫。html
爲了解決以上問題,Vuex 容許咱們將 store 分割成模塊(module)。每一個模塊擁有本身的 state、mutation、action、getter、甚至是嵌套子模塊——從上至下進行一樣方式的分割,今天咱們也來簡單瞭解一下他的使用,深刻學習可能仍是要去看官方文檔vue
文件結構的話,模塊化的使用要多一個 modules 的文件夾,裏面放着細分模塊的 js 文件/模塊名文件夾。git
這裏官方的標準是一個模塊一個 js 文件,可是要是模塊太複雜的話,也能夠把裏面的代碼拆分出來。github
// store 文件夾 │ actions.js │ getters.js │ index.js │ mutations.js │ state.js │ └─modules │ moduleB.js │ └─moduleA index.js mutation.js state.js
而後在建立 store 的 js 文件中引入這些模塊,直接vuex
import moduleA from './modules/moduleA/index' import moduleB from './modules/moduleB'; export default new Vuex.Store({ state, getters, mutations, actions, modules: { moduleA, moduleB, } });
模塊內部的 getter,mutation 和 action,他們方法接收的參數會和根狀態的不同,咱們一個一個來async
getter 的話,他會有三個參數,第一個是模塊內的 state,第二個是 模塊內的 getters,第三個是根節點狀態 rootState,ide
const getters = { bFullName: (state, getters, rootState) => `full${state.bName}` }
mutation 裏面的回調函數傳入的第一個參數也是 模塊內的 state,其餘和根狀態定義的時候同樣模塊化
const mutations = { // 這裏的 `state` 對象是模塊的局部狀態 SET_B_NAME(state, payload) { debugger state.bName = payload.name; } }
最後的 action 的話,他傳入仍是隻有 context 對象,而後咧,這個對象裏面的 state 屬性指模塊內的狀態,rootState 指根狀態,以下函數
const actions = { ASYNC_SET_NAME({ state, commit, rootState }, payload) { setTimeout(() => { state.bName = 'asyncName' }, 4000) } }
這個的話要在原來狀態名前面加一個模塊名才能放到到模塊內的對象。具體以下學習
// 原先的基礎上加個模塊名 this.$store.state.moduleB.bName; // 輔助函數也同樣,name 前面加個模塊名 Deno ...mapState({ name: state => state.moduleB.bName, })
getter,mutation,action 他們默認都是註冊在全局命名空間的,因此咱們默認是能夠和使用根狀態同樣去使用他們,可是這樣不可避免會出現命名衝突的問題,因此使模塊有更高的封裝性與複用性,咱們能夠經過添加 `
namespaced: true` 使其成爲帶命名空間的模塊。當模塊被註冊後,它的全部 getter、action 及 mutation 都會自動根據模塊註冊的路徑調整命名。
// moduleB 模塊導出的時候加個 namespaced: true, export default { namespaced: true, state, getters, mutations, actions, }
由於有了命名空間這麼一層封裝,因此咱們在用輔助函數的時候都要多加那麼一層模塊名,具體看下面代碼。
// getter this.$store.getters['moduleB/bFullName']; ...mapGetters({ bGetter2: 'moduleB/bFullName' }) // mutation this.$store.commit('moduleB/SET_B_NAME', { name: 'QQ' }); ...mapMutations({ setBname: 'moduleB/SET_B_NAME' }), // action this.$store.dispatch('moduleB/ASYNC_SET_NAME', { name: "JJ" }); ...mapActions({ aSetAge: 'moduleB/ASYNC_SET_NAME', }),
每次都要寫模塊名,這樣寫下來很煩,因此這些輔助函數給咱們提供了一個參數位來綁定命名空間。
// moduleB 模塊內的 bName ...mapState('moduleB', { name: state => state.bName }) // 同理 mapAction mapMutation 也能夠這個樣子 ...mapAction('moduleB',[ '/ASYNC_SET_NAME' ])
除了這個以外,若是你當前組件用的 vuex 狀態都是一個模塊的話,咱們可使用 createNamespacedHelpers
建立基於某個命名空間輔助函數,以下:
import { createNamespacedHelpers } from 'vuex' const { mapState, mapActions } = createNamespacedHelpers('moduleB') // moduleName
這樣建立以後,咱們就能夠用以前的寫法來訪問到模塊的狀態。
...mapState({ bName: state => state.bName, }),
若是你但願使用全局 state 和 getter,rootState 和 rootGetter 會做爲第三和第四參數傳入 getter,也會經過 context 對象的屬性傳入 action。
若須要在全局命名空間內分發 action 或提交 mutation,將 { root: true } 做爲第三參數傳給 dispatch 或 commit 便可。具體看下面代碼:
modules: { foo: { namespaced: true, getters: { // 在這個模塊的 getter 中,`getters` 被局部化了 // 你可使用 getter 的第四個參數來調用 `rootGetters` someGetter (state, getters, rootState, rootGetters) { getters.someOtherGetter // -> 'foo/someOtherGetter 模塊內的 getter' rootGetters.someOtherGetter // -> 'someOtherGetter 全局的getter' }, someOtherGetter: state => { ... } }, actions: { // 在這個模塊中, dispatch 和 commit 也被局部化了 // 他們能夠接受 `root` 屬性以訪問根 dispatch 或 commit someAction ({ dispatch, commit, getters, rootGetters }) { getters.someGetter // -> 'foo/someGetter' rootGetters.someGetter // -> 'someGetter' dispatch('someOtherAction') // -> 'foo/someOtherAction' 模塊內的 action dispatch('someOtherAction', null, { root: true }) // ->'someOtherAction' 全局的 action commit('someMutation') // -> 'foo/someMutation' 模塊內的 action commit('someMutation', null, { root: true }) // -> 'someMutation' 全局 mutation }, someOtherAction (ctx, payload) { ... } } } }
這個感受和維護模塊的封裝性有點衝突,可是既然做者提出來了,那就學吧,當咱們想要咱們模塊內的某個 action 提高爲全局 action 的時候,在他聲明的時候,添加 root: true
,並將 action 的定義放到 hanler 函數中,具體以下:
const actions = { // 模塊內 action [ASET_AGE]({ commit }, payload) { setTimeout(() => { commit('SET_B_NAME', payload.name); }, 2000) }, // 提高到全局的 action globalAction: { root: true, handler({ commit }, payload) { debugger setTimeout(() => { commit('SET_B_NAME', payload.name); }, 2000) } } }
關於模塊使用 Vuex 的介紹就說到這裏了,這兩篇筆記的項目源碼我發到了 GitHub 上面,你們能夠去看一下,要是項目中有啥不明白的或者我說的有問題的,歡迎你們留言指正。