state
- 作用:相当于vue中的data,用于存储状态,是唯一数据源,而且是只读,不能做直接修改。
- 语法:
const store = new Vuex.Store({ state: { text:'hello world' }})
- 调用:
// 方法1store.state.text// 方法2(需要使用vue.use注入)this.$store.state.text// 方法3,通过辅助函数mapStateimport { mapState } from 'vuex';export default { computed: { // 使用ES6的扩展运算符来达到将state释放出来 ...mapState([ // 映射 this.text 为 store.state.text 'text' ]) }}
注意:如果一般state初始化时最好就设置好所需属性,如果真的需要动态需改某一个属性,可以如下:
1)Vue.set(obj, 'newProp', 123)2)state.obj = { ...state.obj, newProp: 123 }getter
- 作用:相当于vue中的computed,作用也是类似的。
- 语法:
const store = new Vuex.Store({ state: { text:'hello world' }, getters: { // 第一个参数固定是state对象,第二个参数固定是getters对象 getText: (state, getters) => { return state.text + ' xiaoming'; }, // getters方法中调用getters方法 getGettersText: (state, getters) => { return getters.getText; }, // getters方法返回一个函数 getFuncText: (state,getters) => (name) => { return state.text + ' ' + name; } }})
- 调用:
// 方法1store.getters.getText// 方法2this.$store.getters.getText// 方法3,通过辅助函数mapGettersimport { mapGetters } from 'vuex'export default { computed: { ...mapGetters([ 'getText', 'getGettersText', 'getFuncText' ]) }}
mutation
- 作用:相当于vue中data对象的的set方法,是唯一可以改变state数据的方式,定位是同步改变,即在mutation的方法中不支持异步逻辑,这个的具体原因是因为mutation类似于事件监听的回调函数,而任何在回调函数中进行的状态的改变都是不可追踪的。
- 语法:
const store = new Vuex.Store({ state: { text:'hello world' }, mutations: { // 第一个参数固定是state,剩下还可以再传入一个或0个参数(也叫载荷),这个载荷参数一般是对象,方便传入多个值 changeText (state, payload) { // 变更状态 state.text = 'welcome' + payload.name; } }})
- 调用:
// 方法1,只是第二个参数是载荷store.commit('changeText', { name: 'xiaoye'})// 方法2,相当于整个对象都是载荷store.commit({ type: 'changeText', name: 'xiaoye'})// 方法3this.$store.commit('changeText', { name: 'xiaoye'})// 方法4,依赖辅助函数mapMutations import { mapMutations } from 'vuex';export default { methods: { // 将this.changeText({name: 'xiaoye'})映射为this.$store.commit('changeText', {name: 'xiaoye'}); ...mapMutations([ 'changeText' }) }}
action
- 作用:相当于vue中的method,不能直接修改state,只能通过调用mutation中的方法间接改变state,定位是异步改变,当然也可以同步,如果是需要异步改变的逻辑建议写在action中,其实用过action就知道,其实就相当于把本来属于vue中的method中的方法放到vuex中的action中来而已,只是说公共的异步请求不再用写那么多份在不同的method中,只需要写一份放在action中即可。
- 语法:
const store = new Vuex.Store({ state: { text:'hello world' }, mutations: { // 第一个参数固定是state,剩下还可以再传入一个或0个参数(也叫载荷),这个载荷参数一般是对象,方便传入多个值 changeText (state, payload) { // 变更状态 state.text = 'welcome' + payload.name; } }, actions: { // 第一个参数是固定的一个类似store的实例,具有和store实例相同方法和属性,即可以直接调用state,getters,commit,dispatch等;第二个参数同mutations一样,是载荷 asynChangeText (context, payload) { setTimeout(() => { context.commit('changeText', payload.asynName) }, 1000) } }})
- 调用:
// 方法1store.dispatch('asynChangeText', { asynName: 'xiaoMing'})// 方法2store.dispatch({ type: 'asynChangeText', asynName: 'xiaoMing'})// 方法3this.$store.commit('asynChangeText', { asynName: 'xiaoMing'})// 方法4,依赖辅助函数mapActionsimport { mapActions } from 'vuex';export default { // 用法同 mutation 一样 methods: { ...mapActions([ 'asynChangeText' }) }}
module
- 作用:将state模块化和嵌套子模块化,避免state过大,而变得臃肿,不方便管理,每一个模块都包含完整的state、actions、mutations、getters。
- 语法1(默认命名空间):
/** ** 模块化(默认命名空间) */const moduleA = { state: { a: 1, }, mutations: { // 该state包含的是本模块自己以及子模块的state setA (state, payload) {} }, actions: { // 该context除包含本模块自己以及子模块的属性和方法外,还另外多包含rootGetters和rootState两个属性根模块(moduleA)的state和getter getAsynA (context, payload) {} }, getters: { // 这里的rootState和rootGetter等同于根模块(moduleA)的state和getter getA (state, getters, rootState, rootGetter) {} }, // 两个子模块 modules: { moduleB, moduleC }}// 和moduleA模块一样,只是rootState和rootGetter依然表示moduleA这个跟模块而已const moduleB = { state: { }, mutations: { ... }, actions: { ... }}// 同moduleBconst moduleC = { state: { ... }, mutations: { ... }, actions: { ... }}const store = new Vuex.Store(moduleA)
注意:在默认的命名空间中:
1)所有的模块和子模块的mutations和actions都是包含在全局中的,也叫在全局命名空间中。也就是说如果不同的模块中有相同的actions或者mutations是会存在重复注册挂载到全局中的情况的,只不过他们不是覆盖而是追加的关系而已,被调用的顺讯也是按照模块的注册顺序递归调用的。2)所有模块和子模块的getters都是包含在全局中的,不过不同的是如果出现不同模块之间重名的情况,不是追加而是先到先得,即哪一个模块先注册,即使用谁的。
3)而state是仍然是划分模块的,外部如果要调用,调用方式也是按照模块的层级路径来调用的。即:moduleA的状态:store.state;moduleB的状态:store.state.moduleB。
- 调用:
// 调用state,方法1store.state.astore.state.moduleB.b// 调用state,方法2this.$store.state.athis.$store.state.moduleB.b// 调用state,方法3import {mapState} from 'vuex';export default { computed: { ...mapState([ 'a', // 是moduleA的state 'moduleB', // moduleB是一个对象,包含自己以及子模块的state 'c': state => state.a.moduleC.c // moduleC模块下的state可以通过这种方法的形式返回值 ]) }}// 调用getter,方法1store.getters.getAstore.getters.getB// 调用getter,方法2this.$store.getters.getAthis.$store.getters.getB// 调用getter,方法3import { mapGetters } from 'vuex'export default { computed: { ...mapGetters([ 'getA', 'getB' ]) }}// 调用mutations,方法1,和getter相同点都是挂载在全局中,不同点是不同模块中存在相同名称是会按顺序触发的store.commit('setA')store.commit('setB')// 调用mutations,方法2store.commit({ type: 'setA'})// 调用mutations,方法3this.$store.commit('setA')// 调用mutations,方法4import { mapMutations } from 'vuex';export default { methods: { ...mapMutations([ 'setA' }) }}// 调用actions,同mutations一样
- 语法2(命名空间):
/** ** 模块化(命名空间) */const moduleA = { namespaced: true, state: { a: 1, }, mutations: { // 该state包含的是本模块自己以及子模块的state setA (state, payload) {} }, actions: { // 该context除包含本模块自己以及子模块的属性和方法外,还另外多包含rootGetters和rootState两个属性根模块(moduleA)的state和getter getAsynA (context, payload) {} }, getters: { // 这里的rootState和rootGetter等同于根模块(moduleA)的state和getter getA (state, getters, rootState, rootGetter) {} }, // 两个子模块 modules: { moduleB, moduleC }}// 和moduleA模块一样,只是rootState和rootGetter依然表示moduleA这个跟模块而已const moduleB = { // namespaced: true, // 这里如果不设置命名空间的话那moduleC就继承父命名空间 state: { }, mutations: { ... }, actions: { ... }}// 同moduleBconst moduleC = { namespaced: true, state: { ... }, mutations: { ... }, actions: { ... }, modules: { moduleD: { namespaced: true, state: { d: 1, }, mutations: {}, actions: {} } }}const store = new Vuex.Store(moduleA)
注意:在命名空间中:
1)所有的模块和子模块的mutations、actions、getters都是包含在各自的命名空间或父命名空间中,即自动根据模块注册的路径调整命名。2)而state不受影响,因为默认state也已经是层级嵌套的了。
- 调用
// 调用state,方法4(前三个方法和默认命名空间类似)computed: { ...mapState('moduleC/moduleD', { d: state => state.d }), ...mapState('moduleC/moduleD', ['d']) // 这两种是一样的,只是写法不同},// 调用state,方法5(通过辅助函数createNamespacedHelpers)import { createNamespacedHelpers } from 'vuex';const { mapState } = createNamespacedHelpers('moduleC/moduleD');export default { computed: { // 在 `moduleC/moduleD` 中查找 ...mapState({ d: state => state.d }) }}// 其他的getter、mutations、actions也是和state类似的以上的方法
plugins
- 作用:plugins 是vuex中的一个函数,一般配合 subscribe 函数实现类似于拦截器的效果,而且是一个成功之后的拦截器,是每次 mutation 调用成功之后的钩子,它接收store 实例作为作为唯一的参数。
- 语法:
const myPlugin = store => { // mutation 的格式为:{ type, payload },通过这个对象可以判断是哪一个 mutation 被调用了,额外的参数是什么。 store.subscribe((mutation, state) => { if (mutation.type === 'updateA') { console.log(mutation) console.log(state) } })}const moduleA = { state: { a: 1, }, mutations: { // 被调用完成之后会触发 myPlugin 中的 subscribe 回调 updateA (context, payload) { console.log('A') } }, actions: {...}, getters: {...}, modules: {...}, plugins: [myPlugin]}export default new Vuex.Store(moduleA);
注意:在插件中如果要修改state状态,也需要通过store调用commit,从而触发 mutation 改变state的状态,也就是说不能直接修改state状态。
strict
- 上面一直强调就是修改只能在 mutations 中完成,为了强制约束,可是在vuex实例化的时候传入该属性(严格模式)。
- 语法
const moduleA = { state: {...}, mutations: {...}, actions: {...}, getters: {...}, modules: {...}, plugins: [...], strict: true}export default new Vuex.Store(moduleA);