在前面,咱們已經實現了Vuex
中的getters
,mutations
,actions
,如今,咱們來介紹如下modules
.
對於使用單一狀態樹,應用的全部狀態會集中到一個比較大的對象。當應用變得很是複雜時,store
對象就有可能變得至關臃腫。javascript
爲了解決以上問題,Vuex
容許咱們將 store
分割成模塊(module
)。每一個模塊擁有本身的 state
、mutation
、action
、getter
、甚至是嵌套子模塊——從上至下進行一樣方式的分割:java
let a = {
state:{
name:'a',
age:18
},
modules:{a1,a2,a3},
getters:{
getAlpha(state){
return state.name
},
getAge(state){
return state.age
}
}
...// mutations
...// actions
}
let b = {
state:{
name:'b'
},
modules:{b1,b2,b3},
getters:{
getName(state){
return state.name
}
}
...// mutations
...// actions
}
let rootModule = {
state:{
name:'iamsmiling'
},
modules:{a,b},
getters{
getName(state){
return state.name
}
}
...// mutations
...// actions
}
// 爲了不代碼太過冗餘,這裏沒有給出a1,a2,a3,b1,b2,b3的定義
let store = new Store(rootModule)
複製代碼
根據上面的代碼結構,畫出咱們的state
狀態樹數組
root
/ \
a b
/ | \ / | \
a1 a2 a3 b1 b2 b3
.....// 固然a1,a2,a3,b1,b2,b3也可能存在子模塊
複製代碼
在Vuex
中,咱們想要調用子模塊的getters
,咱們是這樣子進行調用的
store.getters.getAge
咦,等等,root
中的getters
並無定義getAge
啊,爲何能夠這樣調用嗎,調用形式不該該長這樣子的嘛?
store.modules.a.gettters.getAge
嘛,搞不懂,搞不懂....bash
Ok
好吧,那咱們如今就來解釋以,原生Vuex
中能夠store.getters.getAge
這種形式調用的緣由,其實也很簡單,Vuex
不過是將子模塊中的state/getters/mutations/actions
所有安裝到了root
上。這樣講或許有些乾澀難懂,那麼,咱們一樣以上面的例子來進行說明:ui
root = { state:{...} ,modules:{a,b},getters:{getName}
a = {state:{...},getters:{getAlpha,getAge}}
從上面能夠看出,root中的getters只有getName,a的getters中包括getAlpha,getAge.
所謂模塊安裝,不過是子模塊中的state/getters/mutations/actions定義在root上。
通過模塊安裝後,在root的getter中,就包含了getName,getAlpha,getAge
複製代碼
在理解上面的東西以後。咱們明白,接下來咱們的工做就是進行模塊安裝....this
不過,在進行模塊安裝以前,咱們必須先作一項工做,就是進行模塊收集,明確具體有哪些模塊...spa
爲了方便收集模塊,咱們來首先對用戶傳進來的數據進行格式化處理:code
{
raw:rootModule,
state:{name:'iamsmiling'}
children:{
a:{
raw:a,
state:{ name:'a',age:18},
children:{a1,a2,a3}
getters:{getAlpha,getAge} //這裏進行了簡寫
}
b:{
raw:b,
state:{name:'b'},
children:{b1,b2,b3}
getters:{getName} //這裏進行了簡寫
}
},
getters:{getName}//這裏進行了簡寫
}
複製代碼
定義一個類,進行模塊收集對象
class ModuleCollection{
constructor(options){
this.register([],options) // 註冊模塊
}
register(path,rootModule){
let newModule = {
raw: rootModule,
children:{},
state:rootModule.state
}
if(!path.length){
this.root = newModule
}else{
let parent = path.slice(0,-1).reduce((root,current)=>{
return this.root.children[current]
},this.root)
parent.children[path[path.length-1]] = newModule
}
if(rootModule.modules){//若是存在modules選項說明存在子模塊
forEach(rootModule.modules,(name,module)=>{
this.register(path.concat(name),module) // 使用遞歸收集模塊
// 使用例子解析
// 第一次遍歷 this.register([a],a)
// newModule={raw:a,children:{},state:a.state}
// path.silce(0,-1) ==> []
// parent = this.root
// this.root[a] =a
// this.register([a,a1],a1)
// newModule = {raw:a1,children:{},state:a1.state}
// path.slice(0,-1) = [a]
//[a].reduce ===> this.root.children[a]
// parent = a
...
// 第二次遍歷 this.register([b],b)
// newModule={raw:b,children:{},state:b.state}
// path.slice(0,-1) ==> [a]
// parent = this.root
// this.root[b] = b
...
})
}
}
}
複製代碼
注意事項遞歸
concat
返回新數組,slice
返回新數組,不改變原數組reduce
,若是數組爲空,會直接返回咱們傳入的初始值 到目前爲止,模塊收集功能也實現了...