什么是 Module?
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象,当应用变得非常复杂时,store 对象就有可能变得相当臃肿,为了解决以上问题,Vuex 允许我们将 store 分割成模块(module),每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。
模块化的实现
// user 模块
const user = {
state() {
return {
username: 'kobe',
}
},
getters: {
showUsername(state) {
return '用户名:' + state.username
}
},
mutations: {
increment(state) {
console.log('user increment')
}
},
actions: {
incrementAction(context) {
console.log('user incrementAction');
}
},
}
// home 模块
const home = {
state() {
return {
token: 'qqwfdsfsdtgfgdfgdsgergdfs',
}
},
getters: {
showToken(state) {
return 'token 值:' + state.token
}
},
mutations: {
increment(state) {
console.log('home increment');
}
},
actions: {
incrementAction(context) {
console.log('home incrementAction');
}
},
}
// store 实例
const store = createStore({
state() {
return {
counter: 21
}
},
getters: {
showCounter(state) {
return '当前计数:' + state.counter
}
},
mutations: {
increment(state) {
console.log('store increment');
}
},
actions: {
showCounterAction(context) {
console.log(context.state.counter)
},
incrementAction(context) {
console.log('store incrementAction');
}
},
modules: {
user,
home,
},
})
模块化的状态获取
子模块里面的状态是以对象的方式跟 store 实例里的状态合并的。
相当于:
state() {
return {
counter: 21,
user: {
username: 'kobe'
},
home: {
token: 'qqwfdsfsdtgfgdfgdsgergdfs',
}
}
}
所以获取子模块里的状态,要先获取到对应的模块,再来获取:
<div>{{ $store.state.counter }}</div>
<div>{{ $store.state.user.username }}</div>
<div>{{ $store.state.home.token }}</div>
模块化的 getters
子模块里的 getters 跟 store 实例里的 getters 是直接合并的。如果重名会直接覆盖(属性的重新赋值)。相当于:
getters: {
showCounter(state) {
return '当前计数:' + state.counter
},
showUsername(state) {
return '用户名:' + state.username
},
showToken(state) {
return 'token 值:' + state.token
}
}
所以子模块的 getters 可以直接使用:
<div>{{ $store.getters.showCounter }}</div>
<div>{{ $store.getters.showUsername }}</div>
<div>{{ $store.getters.showToken }}</div>
模块化的 mutations
子模块里的 mutations 跟 store 实例里的 mutations 也是直接合并的。如果重名的话都会保留(事件监听)。相当于:
mutations: {
increment(state) {
console.log('store increment')
},
increment(state) {
console.log('user increment')
},
increment(state) {
console.log('home increment')
}
}
如果我们提交 increment 这个 mutation
this.$store.commit('increment')
可以看到控制台打印了三次,这是因为所有同名的 mutation 都保留下来了,而且是按照导入的顺序保留的。
模块化的 actions
跟 mutations 相同,子模块里的 actions 跟 store 实例里的 actions 也是直接合并的,如果重名的话都会保留。
相当于:
actions: {
incrementAction(state) {
console.log('store incrementAction')
},
incrementAction(state) {
console.log('user incrementAction')
},
incrementAction(state) {
console.log('home incrementAction')
}
}
this.$store.dispatch('incrementAction')
命名空间 namespaced
默认情况下,模块内部的 getter, action 和 mutation 是注册在全局的命名空间中的。我们可以添加 namespaced: true 的方式使其成为带命名空间的模块,当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。
基本使用
// user 模块
const user = {
namespaced: true;
state() {
return {
username: 'kobe',
}
},
getters: {
showUsername(state) {
return '用户名:' + state.username
}
},
mutations: {
increment(state) {
console.log('user increment')
}
},
actions: {
incrementAction(context) {
context.commit('increment')
}
},
}
这时如果想要使用 user 中的 getter、action 及 mutation 就需要调整路径:
this.$store.getters['user/showUsername']
this.$store.commit('user/increment')
this.$store.dispatch('user/incrementAction')
如果在访问时没有带上路径,默认是访问 store 实例中对应的 getter、action 及 mutation。
子模块的 action
如果是在子模块中的 action 中提交当前模块中的 mutation 或者是分发其他action的话,是不用加上模块路径的。
mutations: {
increment(state) {
console.log('user increment')
}
},
actions: {
showUsernameAction(context) {
console.log(123)
},
incrementAction(context) {
context.commit('increment')
context.dispatch('showUsernameAction')
}
}
this.$store.dispatch('user/incrementAction')
如果子模块想提交 store 实例中的 mutation 或者分发 store 实例中的 action,加上一个参数就可以了。
actions: {
incrementAction(context) {
context.commit('increment', null, { root: true })
context.dispatch('showCounterAction', null, { root: true })
}
}
在子模块的 action中,只能提交当前模块或者 store 实例中的 mutation,getter 也是相同,只能使用当前模块或者 store 实例中的 getter。
命名空间的好处
命名空间的目的是为了增加代码的可阅读性,它实际上是在对应的属性名前面加上了模块的名称,这么做的好处有两个,第一是我们在使用的时候就能直观的知道对应的是哪个模块,更方便我们维护。第二是如果模块之间或者模块与 store 实例之间存在重名的属性,使用命名空间就不会出现问题,因为模块里的属性需要加上模块名才能被使用。
模块化时出现重名的情况是怎么处理的?
state: 没有影响,因为子模块里面的状态是以对象的方式跟 store 实例里的状态合并的。
getters:子模块里的 getters 跟 store 实例里的 getters 直接合并
- 如果是
store实例里的getters与子模块的getters重名,以store实例为主。 - 如果是子模块之间重名,以先导入的为主。
mutations: