vuex动态注册嵌套module提供模块内部组件间的数据共享

Posted 左直拳

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vuex动态注册嵌套module提供模块内部组件间的数据共享相关的知识,希望对你有一定的参考价值。

vuex提供了全局性的共享数据。如果数据限于模块内共享,可以采用嵌套module,通过命名空间进行访问。

vue开发的主角是组件。组件在代码解耦、复用、提高可读性方面立下功劳,但组件间共享数据、传递参数却很麻烦,尤其是组件嵌套层次很深的情况。如果是祖宗辈传递参数给儿孙辈还好一些,祖宗provider,儿孙inject;然而这是单向的,儿孙想更改祖宗里的这些值就难了。因为你想用 this.$parent,未必能找到父一辈的组件。就算能找到,this.$parent.$parent...这种方式也让人抓狂。

vuex就是为了解决这个问题的。其工作方式,就是所有组件都能访问、更改vuex对象里的数据。数据是共用的,有组件改了,所有组件看到的都变了。就好像在操作一个全局变量一样。

这样就会有一个问题。由于vuex提供的是全局性的数据共享机制,它的作用域是整个系统,不存在说我只在子系统内声明一个vuex对象,自己访问就好。如果我没有理解错误的话,一个系统,有且只有一个vuex对象。如果工程比较复杂,存在多个子系统,所有共享数据都放在一个vuex对象里,会很拥挤和臃肿。因此vuex提供了module,每个module都是一个store对象,并且可以嵌套。这样可以将子系统、模块的共享数据,存储进vuex对象里的相应module,区分层次。同时,module可以采取动态注册的方式,即当运行子系统或模块的时候,才注册相关module;关闭或退出子系统和模块,注销module。以下是详细说明:

一、创建vuex对象

src/store/index.js,这是面向整个系统的

import Vue from 'vue'
import Vuex from 'vuex'

import user from './module/user'
import app from './module/app'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    //
  },
  mutations: {
    //
  },
  actions: {
    //
  },
  modules: {
    user,
    app
  }
})

二、某模块的store module

某模块的store module(src/projects/dzzhyj/store.js)

const key = 'dzzhyj'

export default {
  install (_this) {
    if (_this.$store.state[key]) {//如果module已经存在,则先注销
      $store.unregisterModule(key)
    }

    _this.$store.registerModule([key], {
      /*
        actions
          1、用于通过提交mutation改变数据
          2、会默认将自身封装为一个Promise
          3、可以包含任意的异步操作

        mutations
          1、通过提交commit改变数据
          2、只是一个单纯的函数
          3、不要使用异步操作,异步操作会导致变量不能追踪
      */
      namespaced: true,//请注意,是namespaced!而不是namespace!这个属性与类似“dzzhyj/product/”
      modules: {
        product: {
          namespaced: true,
          state: {
            v: 'hello world', // for test
            details: []
          },
          mutations: {// 同步操作
            setV (state, val) {
              state.v = val
            },
            setDetails (state, val) {
              state.details = val
            }
          },
          actions: {// 异步操作
            getV ({ state }) {
              return state.v
            },
            keepDetails: ({ commit }, val) => {
              commit('setDetails', val)
            }
          }
        }
      }
    })
  },
  uninstall (_this) {
    _this.$store.unregisterModule([key])
  }
}

三、动态注册store module

下图中,页签容器页、页签都是一个个独立的组件。在页签容器页(即明细信息对话框)注册,“报告”页签写入数据,“地图”页签读取数据。

在模块的明细信息对话框里进行注册store module(src/view/projects/dzzhyj/product/_pop.vue)

<!-- 这是一个弹出框 -->
<template>
  <div>
    <Modal v-model="modal1" :width="width" :styles="{ top: '10px' }" draggable >
		。。。
    </Modal>
  </div>
</template>

<script>
import myStore from '@/projects/dzzhyj/store.js'

export default {
  data () {
    return {
    ...
    }
  },
  created () {
    myStore.install(this) //注册我的store module
  },
  destroyed () {
    myStore.uninstall(this)//注销我的store module
  },
  methods: {
  	...
  }
}
</script>

四、更改数据

src/view/projects/dzzhyj/product/_report.vue

<template>
  <div class="page-container">
	“报告”页签。。。
  </div>
</template>

<script>
export default {
  data () {
	。。。
  },
  methods: {
    keepDetails (val) {
      //想支持这种 'dzzhyj/product/keepDetails' action,store中的namespaced = true
      this.$store.dispatch('dzzhyj/product/keepDetails', val).then(() => {
        console.log('已缓存明细数据')
      })
    }
  }
}
</script>

五、读取数据

“报告”页签的兄弟页签“地图”读取明细数据进行绘制

src/view/projects/dzzhyj/product/_map.vue

<template>
  <div class="map-container">
    "地图"页签。。。
  </div>
</template>

<script>
export default {
  data () {
	。。。
  },
  methods: {
    dyeing (details) {
		//地图绘制
    }
  },
  computed: {
    getDetails () {
      let details = null
      if (this.$store.state.dzzhyj && this.$store.state.dzzhyj.product) {
        details = this.$store.state.dzzhyj.product.details
      }
      return details
    }
  },
  watch: {
    getDetails (val) {
      this.dyeing(val)
    }
  }
}
</script>

六、总结

如果没有vuex,两个并列的页签组件之间,如何传递数据呢?可以将数据通过emit传给容器页,再由容器页传给另一个页签。比较麻烦,也不清晰。

vuex可以很好地解决组件间数据共享的问题。当然,如果明白vuex的原理,自己写代码实现一个store.js之类的组件也可以,但没有必要,就用vuex好了,很方便。之前见过网上一些文章都说,如果参数传递不太多,就没必要用这个vuex;甚至有人说不想用vuex。给人的感觉,就是vuex是个很庞大、笨重、复杂的东西。其实呢,vuex并不复杂,反而很好用,只是有一两个坑,避开就好。

参考文章:
vuex 的动态注册方法 registerModule

以上是关于vuex动态注册嵌套module提供模块内部组件间的数据共享的主要内容,如果未能解决你的问题,请参考以下文章

vuex中module的命名空间概念

Vuex:具有动态命名空间的 createNamespacedHelpers

使用 NuxtJS 和 vuex-module-decorators 的动态 vuex 存储模块

vue路由自动加载、按组件异步载入vuex以及dll优化

vuex的秘籍之vuex的模块化及工具类,样式的配置

Vuex使用教程