Vuex模块化用法 跨模块调用的方式
作者:小杨闯关之情迷代码
准备
为了说明这个问题,我们来一起实现一个小需求
即 现在有两个module - product 和 user
需求为调用 product 模块的方法 去修改 user 模块的 userInfo(用户名信息)
// module user 模块 const user = { state: { userInfo: '鸣人', // 用户信息 }, mutations:{ SET_UserInfo(state,payload) { state.userInfo = payload.userInfo }, }, actions: { setuserInfo(context,payload) { return new Promise(resolve => { context.commit('SET_UserInfo',payload) resolve(); }) }, } } export default user
不难看出, 上述需求 其实就是在 product 模块的方法中的去调用 user模块 的 setuserInfo 方法
那我们来看看 product 模块
const product = { actions: { callsetuserInfo(context,payload) { // 在这里调用 user 模块的 setuserInfo 方法 }, } } export default product
接着就是注册这两个模块:
import Vue from 'vue' //引用Vuex import Vuex from 'vuex' Vue.use(Vuex) import product from '@/store/modules/product' import user from '@/store/modules/user' // import getters from '@/store/modules/getters.js' // import actions from '@/store/modules/actions.js' //实例store对象 const store = new Vuex.Store({ modules: { product, user // getters, // actions } }) //导出store对象 export default store
跨模块调用state
这里我们首先要了解 方法中的第一个参数 context
打印一下
发现有 commit,dispatch,getters,rootGetters,rootState 几个参数
结合官网说明:
同样,对于模块内部的 action,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState
即: context.state -> 访问的是 当前模块下的 state
context.rootState -> 是根节点状态
const product = { actions: { callsetuserInfo(context,payload) { // 通过 根节点状态 去访问 user 模块的 userInfo信息 console.log(context.rootState.user.userInfo) // '鸣人' }, } } export default product
跨模块调用getter
和跨模块调用state类似 ,通过 context.rootGetters去访问模块
namespaced情况区分
跨模块调用mutation,action
这里要区分 模块是否开启了命名空间 namespaced
首先来看默认情况 (没有开启namespaced)
官网说明:
- 默认情况下,模块内部的 action 和 mutation 仍然是注册在全局命名空间的——这样使得多个模块能够对同一个 action 或mutation 作出响应。
- Getter同样也默认注册在全局命名空间,但是目前这并非出于功能上的目的(仅仅是维持现状来避免非兼容性变更)。
- 必须注意,不要在不同的、无命名空间的模块中定义两个相同的getter 从而导致错误。
跨模块调用actions:
// 三个参数: 1. 模块/方法名 2.参数 3.是否从跟节点寻找 context.dispatch('需要调用的方法名',params,{root: true})
跨模块调用mutations:
// 三个参数: 1. 模块/方法名 2.参数 3.是否从跟节点寻找 context.commit('需要调用的方法名',params,{root: true})
const product = { actions: { callsetuserInfo(context,payload) { // 因为是默认为全局注册 可以直接访问 setuserInfo // {root: true} 表明从根节点寻找 如果不加 则是从当前模块中 // 这里即 product模块 去找 setuserInfo 方法 (当然找不到) contxt.dispatch('setuserInfo',{ userInfo: '宇智波佐助' },{root: true}) }, } } export default product
在页面中调用:
...mapState({ cartList: state => state.product.cartList, userInfo:state => state.user.userInfo, }), methods: { // 因为为默认情况,Action全局注册,这里使用辅助函数直接取值 ...mapActions( [ 'callsetuserInfo', ]), async onLoad(params) { this.callsetuserInfo().then(()=> { // 打印user 模块 的 userInfo console.log(this.userInfo) // 宇智波佐助 }) }
打印设置值- 宇智波佐助 ,默认情况(未开启命名空间)跨模块调用actions 成功
跨模块调用mutations类似,语法糖改为 context.commit 即可
启命名空间的情况
官方文档:
- 如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true的方式使其成为带命名空间的模块。
- 当模块被注册后,它的所有 getter、action 及 mutation都会自动根据模块注册的路径调整命名。
例如:
const store = createStore({ modules: { account: { namespaced: true, // 模块内容(module assets) state: () => ({ ... }), // 模块内的状态已经是嵌套的了,使用 `namespaced` 属性不会对其产生影响 getters: { isAdmin () { ... } // -> getters['account/isAdmin'] }, actions: { login () { ... } // -> dispatch('account/login') }, mutations: { login () { ... } // -> commit('account/login') }, // 嵌套模块 modules: { // 继承父模块的命名空间 myPage: { state: () => ({ ... }), getters: { profile () { ... } // -> getters['account/profile'] } }, // 进一步嵌套命名空间 posts: { namespaced: true, state: () => ({ ... }), getters: { popular () { ... } // -> getters['account/posts/popular'] } } } } } })
官网中的 在带命名空间的模块内访问全局内容 的例子:
modules: { foo: { namespaced: true, getters: { // 在这个模块的 getter 中,`getters` 被局部化了 // 你可以使用 getter 的第四个参数来调用 `rootGetters` someGetter (state, getters, rootState, rootGetters) { getters.someOtherGetter // -> 'foo/someOtherGetter' rootGetters.someOtherGetter // -> 'someOtherGetter' rootGetters['bar/someOtherGetter'] // -> 'bar/someOtherGetter' }, someOtherGetter: state => { ... } }, actions: { // 在这个模块中, dispatch 和 commit 也被局部化了 // 他们可以接受 `root` 属性以访问根 dispatch 或 commit someAction ({ dispatch, commit, getters, rootGetters }) { getters.someGetter // -> 'foo/someGetter' rootGetters.someGetter // -> 'someGetter' rootGetters['bar/someGetter'] // -> 'bar/someGetter' dispatch('someOtherAction') // -> 'foo/someOtherAction' dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction' commit('someMutation') // -> 'foo/someMutation' commit('someMutation', null, { root: true }) // -> 'someMutation' }, someOtherAction (ctx, payload) { ... } } } }
好了,了解之后 。回到我们的需求 = =!
模块user,product 先 开启命名空间 如下:
const user = { namespaced: true, // 后续代码 }
在product模块 中去调用user 模块的action方法
const product = { actions: { callsetuserInfo(context,payload) { // 因为开启了命名空间 访问方法 需要通过模块 user/setuserInfo context.dispatch('user/setuserInfo',{ userInfo: '宇智波佐助' },{root: true}) }, } } export default product
在页面中调用
...mapState({ cartList: state => state.product.cartList, userInfo:state => state.user.userInfo, }), methods: { // 因为为开启命名空间 不能直接访问方法 // 普通写法 ...mapActions([ 'product/callsetuserInfo', ]), // 简化写法: 将模块的空间名称字符串作为第一个参数传递 ...mapActions('product',[ 'callsetuserInfo', ]), // 如果想调用多个不同命名空间的方法 ...mapActions('模块B',[ '模块B Function', ]), async onLoad(params) { this.callsetuserInfo().then(()=> { // 打印user 模块 的 userInfo console.log(this.userInfo) // 宇智波佐助 }) }
参考文档: https://vuex.vuejs.org/zh/guide/modules.html
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。