如何复用使用store的Vue业务组件

2,829 阅读1分钟

背景

之前公司业务做了一个审核功能,业务数据和状态比较复杂,当初做的时候用上了 Vuex store 进行数据交互,最近新上了基于审核功能页面模板的需求,依照其模板开发不同的功能(不同菜单入口模板相同,只有api不相同),在改造的过程中遇到了 store 组件如何进行复用的问题。

问题

审核系统是可以菜单多开的,也就是同一个模板生成的菜单需要具备同时打开使用的功能,我们知道 vue 中组件是可以复用的,每次引用都是生成一个新的实例,但组件中引入了 store 后导致不同实例共享同个 store,数据就会产生混淆

方法一:改造成互斥菜单

当模板菜单中其中一个已经打开的情况下,另外模板菜单不能继续打开,并弹出提示需要先关闭已打开的xx菜单,需要用this.$router.push替代<router-link>,监听绑定事件@click判断是否需要新开菜单后执行 push 操作,此方法限制了多开页面的功能

方法二:尝试不用菜单引用不同store

然后我就开始思考,是否可以通过动态修改mapStatemapActionsmapMutations的首个参数(muduleName)达到引用不同 store 呢?

mapState首个参数不能获取 this,所以不能动态修改 moduleName;那是否可以不用mapxxx函数直接调用呢,答案是可以的,但是需要修改的地方太多,不利于做改造

方法三:尝试动态注册

vuex.vuejs.org/zh/guide/mo…

动态注册也是可行的,但需要注册不一样的 moduleName,然后问题还是回到了方法二,只是从静态注册变成了动态注册

方法四:组件注册store

和方法三不一样的是,方法三是注册 module,而这是注册整个 store

我们可以通过注册新 store 的方式注册 module,并且 module 会变为 组件内全局 store,这个方法只需要将原本引用的 moduleName 去掉,其他代码可以维持不动,最低成本达到 store 组件复用

ps:如果需要引用外部 store,可用this.$root.$store访问,mapxxx方法不可访问外部 store

总结

如果在设计之初就知道需要复用组件的话,组件内最好不要用 store,因为 store 的用处是共享整个 vue 应用数据,方法四虽然可行但却破坏了这种模式,导致外部组件无法访问其内部重新注册的 store(当然可以通过动态注册module的方式注册进全局 store)

[更新]通过动态注册module的方式注册进全局 store

// 统一管理的mixin
import Base from '@/page/base';
import module from '@/store/modules/module';
import Vuex from 'vuex';

export default function(menuName) {
  return {
    store: new Vuex.Store(module),
    components: { Base },
    created() {
      const rootStore = this.$root.$store;
      // 动态注册module,此时两份state不同步
      rootStore.registerModule(menuName, {
        ...module,
        namespaced: true,
      });
      // 同步更新rootStore.state[menuName]
      this.$store.subscribe(mutation => {
        rootStore.commit(`${menuName}/${mutation.type}`, mutation.payload);
      });
    },
  };
}

作者其他文章:

分享个人用于开发相关的软件/工具

解读并实现一个简单的koa-router

关于element el-button使用$attrs的一个注意要点

github: github.com/masongzhi