Vuex由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
因此,在项目中,如果需要用到Vuex的话,Vuex 允许我们将 store 分割成模块(module),每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。
默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的,这样使得多个模块能够对同一 mutation 或 action 作出响应。如果希望你的模块具有更高的封装度和复用性,此时就用到了命名空间这个概念。
1.如何使模块成为一个命名空间模块?
你可以在单个模块中通过添加namespaced:true的方式使其成为带命名空间的模块。
const moduleA ={
namespaced:true, //开启namespace:true,该模块就成为命名空间模块了
state:{
count:10,
countA:888
},
getters:{...},
mutations:{...},
actions:{...}
}
2.组件中如何获取带有命名空间moduleA中的state数据?
注意:mapState辅助函数方式需要把mapState放进组件的计算属性中使用,也就是说使用mapState辅助函数返回的结果要放到组件的计算属性中使用。
export default{
computed:{
// 1、基本(传统)方式:state需要带上模块名
this.$store.state.moduleA.countA
// 2、mapState辅助函数方式
// ① 通过mapState的对象来赋值:需要指定模块名称 moduleB
...mapState({
count:state=>state.moduleB.countB
})
// ② 通过mapState的数组来赋值:需要指定模块名称 moduleB
...mapState('moduleB',['countB'])
}
}
◆ 获取state数据与组件中调用Vuex的state,getters,mutations,actions,modules的数据传递、传参问题 中的1.State中的取法一样
3.组件中调用命名空间模块中的getters
注意:mapGetters辅助函数方式需要把mapGetters放进组件的计算属性中使用,也就是说使用mapGetters辅助函数返回的结果要放到组件的计算属性中。
export default {
computed: {
// 共有三种方式,如下:
// 第1种:传统方式
commonGetter(){
this.$store.getters['moduleA/moduleAGetter']
},
// 第2种:指定模块的名称 moduleA
...mapGetters('moduleA',['moduleAGetter']) // 此处的moduleA,不是以前缀的形式出现!!!
//第3种:别名状态下
...mapGetters({
paramGetter:'moduleA/moduleAGetter'
)}}}
4.组件中调用命名空间模块中的Mutations
注意:mapMutations辅助函数方式需要放进组件的methods中使用,也就是说使用mapGetters辅助函数返回的结果要放到组件的methods中使用。
methods: {
// 共有三种方式,如下:
//1,3加个前缀moduleA/,都可以实现。2使用辅助函数未变名称的特殊点!!!
// 1.
commonMutation(){
this.$store.commit('moduleA/moduleAMutation');
},
// 2.
...mapMutations('moduleA',['moduleAMutation']),
//3.别名状态下
...mapMutations({
changeNameMutation:'moduleA/moduleAMutation'
})}
5.组件中调用命名空间模块中的Actions(与mutations一致)
methods:{
// 共有三种方式,如下:
// 1,3加个前缀moduleA/,都可以实现。2使用辅助函数未变名称的特殊点!!!
//1.
commonAction(){
this.$store.dispatch('moduleA/moduleAAction')
},
//2.
...mapActions('moduleA',['moduleAAction']),
//3.别名状态下
...mapActions({
changeNameAction:'moduleA/moduleAAction'
})}
6.带命名空间的moduleA,moduleB模块中,如何获取根store,当前模块,兄弟模块中的action,mutations ,getters方法?
获取根store模块中的:
state数据: 通过rootState参数 即:rootState.属性名
getter方法:通过rootGetters参数来获取 即:rootGetters.increNum
附:向根getters中传递参数方式:rootGetters.increNum( { id:11,name:'lucy' } );
根store中getters定义接多参数:
getters: { //目前个人研究:只能传递一个参数,或者一个对象
increNum:(state)=>(obj)=>{
console.log(obj)
}
}
提交mutations:commit('increment',null,{root:true}); // increment为根store中的mutation
分发actions:dispatch('incrementAction',null,{root:true}); // incrementAction为根store中的action
参数部分示例:
actions:{
moduleAAction({state,commit,dispatch,getters,rootState,rootGetters}){
//处理逻辑
}
}
获取当前模块中的:
state数据:通过state参数来获取 即:state.属性名
getter方法:通过getters参数来执行 即:getters.moduleAIncreNum(); //传递参数:可以是多个,也可以是一个obj对象
提交mutations:通过commit参数来执行 即:commit('moduleAMutation);
分发actions:通过dispatch参数来执行 即:dispatch('nextmoduleAAction');
参数部分示例:
actions:{
moduleAAction({state,commit,dispatch,getters,rootState,rootGetters}){
//处理逻辑
}
}
获取兄弟模块中的:(当前模块名:moduleA)
state数据:通过rootState参数来获取 即:rootState.moduleA.属性名
getter方法:通过getters参数来执行 即:rootGetters['moduleB/moduleBGetter']
提交mutations:通过commit参数来执行 即:commit('moduleB/moduleBMutation',{},{root:true});
分发actions:通过dispatch参数来执行 即:dispatch('moduleB/moduleBAction',{},{root:true});
7.在带命名空间的模块中,如何将action注册为全局actions
两个条件:
①添加 root: true
②并将这个 action 的定义放在函数 handler 中
// storeAction在命名空间moduleA中,但是它是一个全局actions
const moduleA = {
namespaced:true,
storeAction:{
root:true, // 条件1
handler(namespacedContext, payload){ // 条件2:handler
// namespacedContext 上下文信息
// payload 载荷,即参数
console.log(namespacedContext)
console.log(payload)
alert("我是模块A中的全局storeAction")
}
}
}
8.当使用 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']()
])
}
解决办法:对于这种情况,你可以将模块的空间名称字符串作为第一个参数传递给上述函数,这样所有绑定都会自动将该模块作为上下文。于是上面的例子可以简化为:
computed: {
...mapState('some/nested/module', {
a: state => state.a,
b: state => state.b
})
},
methods: {
...mapActions('some/nested/module', [
'foo', // -> this.foo()
'bar' // -> this.bar()
])
}
9.除了8中的将空间名称作为第一个参数传递外,还有其它别的方法吗?
你可以通过使用 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'
])
}
}
部分内容摘自 Vuex 官方文档:Module | Vuex
参考资料
Vuex 模块的基础使用--命名空间
Vuex的Modules以及命名空间 | 深入理解Vuex常见问题
Vuex 使用总结 | Vuex的模块详解