## **一:Module**
>[success]Vuex 允许我们将 store 分割成**模块(module)**。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块
~~~
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
~~~
## **二:模块的局部状态**
对于模块内部的 mutation 和 getter,接收的第一个参数是**模块的局部状态对象**。
~~~
const moduleA = {
state: { count: 0 },
mutations: {
increment (state) {
// 这里的 `state` 对象是模块的局部状态
state.count++
}
},
getters: {
doubleCount (state) {
return state.count * 2
}
}
}
~~~
同样,对于模块内部的 action,局部状态通过`context.state`暴露出来,根节点状态则为`context.rootState`:
~~~
const moduleA = {
// ...
actions: {
incrementIfOddOnRootSum ({ state, commit, rootState }) {
if ((state.count + rootState.count) % 2 === 1) {
commit('increment')
}
}
}
}
~~~
对于模块内部的 getter,根节点状态会作为第三个参数暴露出来:
~~~
const moduleA = {
// ...
getters: {
sumWithRootCount (state, getters, rootState) {
return state.count + rootState.count
}
}
}
~~~
## **命名空间**
**默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的**
##
如果希望你的模块具有更高的**封装度**和**复用性**,使用命名空间后可以在模块内部嵌入子模块,并且无需修改代码,只需要在模块中设置 `namespaced: true`即可。(例如在工单模块下嵌入预约单等等)
~~~
const store = new Vuex.Store({
modules: {
trade: {//工单模块
namespaced: true,
// 模块内容(module assets)
state: { ... }, // 模块内的状态已经是嵌套的了,使用 `namespaced` 属性不会对其产生影响
getters: {
isAdmin () { ... } // -> getters['trade/isAdmin']
},
actions: {
login () { ... } // -> dispatch('trade/login')
},
mutations: {
login () { ... } // -> commit('trade/login')
},
// 嵌套子模块
modules: {
// 继承父模块的命名空间
schedule: { //预约单模块
state: { ... },
getters: {
profile () { ... } // -> getters['trade/profile']
}
},
// 进一步嵌套命名空间
posts: {
namespaced: true,
state: { ... },
getters: {
popular () { ... } // -> getters['trade/posts/popular']
}
}
}
}
}
})
~~~
## **在带命名空间的模块内访问根模块**
* 如果想要访问根模块的`state`和`getter`,只需要在第三和第四个参数传入`rootState`和`rootGetters`即可。
* 如果想触发根模块的`action`和`mutation`,只需要将`{ root: true }`作为第三参数传给`dispatch`或`commit`即可。
~~~
modules: {
foo: {
namespaced: true,
getters: {
// 在这个模块的 getter 中,`getters` 被局部化了
// 你可以使用 getter 的第四个参数来调用 `rootGetters`
someGetter (state, getters, rootState, rootGetters) {
getters.someOtherGetter // -> 'foo/someOtherGetter'
rootGetters.someOtherGetter // -> 'someOtherGetter'
},
someOtherGetter: state => { ... }
},
actions: {
// 在这个模块中, dispatch 和 commit 也被局部化了
// 他们可以接受 `root` 属性以访问根 dispatch 或 commit
someAction ({ dispatch, commit, getters, rootGetters }) {
getters.someGetter // -> 'foo/someGetter'
rootGetters.someGetter // -> 'someGetter'
dispatch('someOtherAction') // -> 'foo/someOtherAction'
dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'
commit('someMutation') // -> 'foo/someMutation'
commit('someMutation', null, { root: true }) // -> 'someMutation'
},
someOtherAction (ctx, payload) { ... }
}
}
}
~~~
## **带命名空间的绑定函数**
当使用了命名空间的模块,要在组件中使用`mapState`,`mapGetters`,`mapActions`和`mapMutations`访问时,写起来会比较繁琐:
~~~
computed: {
...mapState({
a: state => state.some.nested.module.a,
b: state => state.some.nested.module.b
})
},
methods: {
...mapActions([
'some/nested/module/foo', // -> this['some/nested/module/foo']()
'some/nested/module/bar' // -> this['some/nested/module/bar']()
])
}
~~~
针对上述问题Vuex提供了两种方法解决:
**1.将模块的空间名称作为第一个参数传递给`mapState`,`mapGetters`,`mapActions`和`mapMutations`**
**2.使用`createNamespacedHelpers`函数创建带命名空间的`mapState`,`mapGetters`,`mapActions`和`mapMutations`**
>[info] 将命名空间作为参数传递:
~~~
computed: {
...mapState('some/nested/module', {
a: state => state.a,
b: state => state.b
})
},
methods: {
...mapActions('some/nested/module', [
'foo', // -> this.foo()
'bar' // -> this.bar()
])
}
~~~
>[info] 使用`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'
])
}
}
~~~