modules
modules也属于vuex的核心概念之一
为什么要使用模块化?
一个项目的数据会是很庞大的,所以如果将所有的数据都写在一起,那么mutations,actions,getters都写在一起,那么store的结构会变得相当臃肿,也不利于程序的维护与阅读
所以我们可以将数据分割成多个模块,每个模块又都存在state,mutations, actions,getters这些核心概念
项目结构
大型项目
store
├── index.js # 组装模块并导出 store 的地方
├── actions.js # 根级别的 action
├── mutations.js # 根级别的 mutation
└── modules
├── login.js # 登录模块
└── products.js # 产品模块
一般也可以只需要index.js和modules,根据你的项目而定
store
├── index.js # 组装模块并导出 store 的地方
└── modules
├── login.js # 登录模块
└── products.js # 产品模块
开始
- index.js
import Vue from "vue"
import Vuex from "vuex"
import home from './modules/home' // 引入对应的模块
import login from './modules/user' // 引入对应的模块
Vue.use(Vuex)
// 向外暴漏store对象
export default new Vuex.Store({
modules: {
home,
login
},
// 以下属于根节点的
state: {},
mutations: {},
actions: {},
getters: {}
})
- main.js导入store对象并挂载到vue的实例对象上
import store from './store'
new Vue({
render: h => h(App),
store
}).$mount('#app')
- 以模块中的other.js为例
const RECEIVE_TOKEN = 'RECEIVE_TOKEN'
/**
* 这里的state只是属于当前模块的state,,不是总的state
*/
const state = {}
const mutations = {
/**
* 为了方便维护,这里的事件名,一般定义成一个常量
* 或者你也可以单独再定义一个常量模块,将模块再导入进来
*/
/**
* 当然这里的参数的state也是指当前模块的state
*/
RECEIVE_TOKEN(state, token) {...},
}
const actions = {
/**
* 其中context中的属性也发生了变化
* - context.state 当前模块的state
* - context.rootState 根节点的state
* - context.getters 当前模块的getters
* - context.rootGetters 根节点的getters
*/
async userRegister(context, info) {...},
// async userRegister({state, rootState}, info) {...},
}
const getters = {
/**
* 每一个getter中有四个参数了
* - state: 当前模块的状态
* - getters:当前模块的getters,对象类型
* - rootState:根节点的state状态
* - rootGetters: 根节点的getters
*/
test(state[, getters, rootState, rootGetters]){ return ... }
}
export default {
state,
mutations,
actions,
getters
}
访问属性
-
state
因为使用了模块化,在组件中使用this.$store.state方法访问state数据时
从上面的例子中可以看出,定义在根节点的状态会直接作为state的一个属性,模块的名字作为state的对象类型的一个属性,这个对象里面存储着当前模块的state状态。
说白了在vue组件中访问根节点的state状态直接this.$store.state.(状态名);访问模块中的state就要:this.$store.state.(模块名).(模块内state状态名)
如果是使用mapState函数的话,映射根节点的state可以简写,访问模块内的state就不行了
import {mapState} from 'vuex'
computed: {
// 根节点的state
...mapState(['haha'])
// 访问模块内的state
...mapState({
modules:state => state.login.modules
})
}
- getters,mutations,actions通过store对象调用和mapXxx的方法调用都没有改变,不用向上面的state的方法用:模块名.xxx;的形式调用,也就是不论是根节点和模块内部的getters,mutations,actions全都是定义在全局的。
命名空间(以下示例中模块都开启了命名空间)
上面说到不论是根节点和模块内部的getters,mutations,actions全都是定义在全局的,你可能会觉得这样不是很“模块化”或者你希望的模块具有更高的封装度和复用性,那么你可以添加命名空间
// 模块login.js
export default {
// 添加一个 namespaced属性即可开启命名空间
namespaced: true,
state: {
modules: 'modules'
},
mutations: {
RECEIVE_DATA(){
console.log(1);
}
},
actions: {
test(conetxt) {
console.log(12);
}
},
getters: {
ads(state, getters, rootState) {
return 'xxx'
},
modulesGetter() {
return 'modulesGetter'
}
}
}
开启命名空间之后所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名
import Vue from "vue"
import Vuex from "vuex"
import login from './modules/login' // 引入对应的模块
Vue.use(Vuex)
// 向外暴漏store对象,当然还要在main中导入并挂载到vue的实例对象上
export default new Vuex.Store({
modules: {
login
}
getters: {
rootGetter(){
return 'rootGetter'
}
}
})
然后在app.vue中打印出全局的getters
<template>
<div><button @click="asdf">dianwo</button>
</div>
</template>
<script>
import {mapGetters} from 'vuex'
export default {
methods: {
asdf() {
console.log(this.$store.getters);
},
},
};
</script>
<style scoped>
</style>
因为现在名字就特殊了,在组件中就得使用this.$store.getters['getterName']的方法了
this.$store.getters['login/ads']
然后actions类似
this.$store.dispatch('login/test')
mutation也一样
this.$store.dispatch('login/RECEIVE_DATA')
一般都是通过action提交一个mutation,所以在模块内commit就不用加login
actions: {
test(conetxt) {
conetxt.commit('RECEIVE_DATA')
}
}
全局调用actions和commit
如果要在任何一个模块中分发action和提交commit,比如说在模块中调用根节点的action
只需要在dispatch中传入第三个参数{root: true},commit也是类似,第二个参数null,不能省略
test1({ dispatch, commit }) {
dispatch('test3', null, {root: true})
commit('根节点的mutation名字', null, {root: true})
console.log("模块内的test1事件");
}
组件中使用Mapxxxx函数
在使用是也得加上空间名称,所以就比较麻烦,vuex也为我们简化了操作
函数接受两个形参,第一个是字符串,就是空间名称(模块的名字),第二个参数mapState,mapGetters接受一个对象,mapActions和mapMutations接受一个数组
模块login.js
export default {
namespaced: true,
state: {
modules: 'modules'
},
mutations: {
RECEIVE_DATA() {
console.log(1);
}
},
actions: {
test3() {
console.log("模块内的test2事件");
}
},
getters: {
titleArr(){
return "模块的getter"
}
}
}
vue组件
import {mapState, mapGetters, mapMutations, mapActions} from 'vuex'
export default {
methods: {
...mapActions('login', [
'test3' // => this.test3()
])
,
...mapMutations('login', [
'RECEIVE_DATA' // => this.RECEIVE_DATA()
])
},
computed: {
...mapState('login', {
a: state => state.modules
}),
...mapGetters('login', {
b: 'titleArr'
})
}
}