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,) {
state.v = val
},
setDetails (state,) {
state.details = val
}
},
actions: {// 異步操作
getV ({ state }) {
return state.v
},
keepDetails: ({ commit },) => {
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傳給容器頁,再由容器頁傳給另一個頁簽。比較麻煩,也不清晰。