手撕Vuex-提取模块信息
前言
在上一篇【手撕Vuex-模塊化共享數據】文章中,已經了解了模塊化,與共享數據的注意點。
那么接下來就要在我們自己的 Nuex 中實現共享數據模塊化的功能。那么怎么在我們自己的 Nuex 中實現共享數據模塊化的功能呢?
處理數據
也非常的簡單,是不是就是處理一下子模塊的數據,處理一下子模塊的 getters,處理下子模塊的 mutations,處理下子模塊的 actions 就可以了。
那么怎么處理呢?首先我們來看下數據怎么處理。想要知道怎么處理的,我們首先要知道數據是怎么使用的。
數據怎么使用的,我們在組件當中是不是拿到全局的 Store, 拿到全局的 Store 之后,從全局的 store 中拿到子模塊,然后從子模塊中拿到數據,然后在組件當中使用。
所以說我需要怎么做,我們需要將子模塊的一個數據添加到全局的 Store 當中,好了到這里我們就已經了解了數據怎么處理了。
那么接下來我們就來看下 getters/ mutations/ actions 怎么處理。
處理 getters
處理 getters 首先第一條就是,重名的方法不能不進行覆蓋。
處理 mutations
處理 mutations,在 mutations 當中,出現了同名的方法,那么就不能不進行覆蓋。
如果說出現了同名的方法,那么取值就是一個數組,將所有的同名方法都添加到這個數組當中。
然后執行這個同名方法就是循環這個數組,然后執行這個數組當中的每一個方法。
處理 actions
處理 actions,如果說出現了同名的方法,那么取值就是一個數組,將所有的同名方法都添加到這個數組當中(同理可證)。
那么知道了怎么處理了之后,接下來怎么辦呢?我們就來看下代碼怎么寫。如果我們直接處理傳遞進來的數據,可能呢,會比較麻煩,所以說在處理之前呢,我還需要將傳遞進來的數據進行一下子處理,按照我想要的格式進行格式化一下。
格式化數據
在實現之前,我先將我想格式的數據結構貼出來按照這個結構去編寫我們的格式化數據的方法。
let root = {
_raw: rootModule,
_state: rootModule.state,
_children: {
home: {
_raw: homeModule,
_state: homeModule.state,
_children: {}
},
account: {
_raw: accountModule,
_state: accountModule.state,
_children: {
login: {
_raw: loginModule,
_state: loginModule.state,
_children: {}
}
}
}
}
}
那么我們就來看下怎么實現這個方法。
由于實現的方法代碼比較繞,所以我這里單獨開了一個類,來處理這件事情。
這個類的名字叫做 ModuleCollection,這個類的作用就是將傳遞進來的數據進行格式化,然后返回一個格式化之后的數據。
到這里就要步入正題了,我們就來看下這個類的代碼怎么寫。
首先在 Store 類當中,將傳遞進來的數據傳遞到 ModuleCollection 類當中,然后在 ModuleCollection 類當中,將傳遞進來的數據進行格式化,然后返回一個格式化之后的數據。
編寫 ModuleCollection 類的代碼:
class ModuleCollection {
constructor(options) {
this.register([], options);
}
register(arr, rootModule) {
}
}
首先通過構造函數接收傳遞進來的數據,然后在構造函數當中,調用 register 方法,將傳遞進來的數據傳遞進去。
然后在 register 方法當中,接收兩個參數,第一個參數是一個數組,第二個參數是一個對象。
第一個參數是一個數組,這個數組是用來存儲模塊的名字的,第二個參數是一個對象,這個對象是用來存儲模塊的數據的。
第一個參數是數組也是我想用來區分是根模塊還是子模塊的,如果說是根模塊,那么這個數組就是空的,如果說是子模塊,那么這個數組就是有值的。
好了我們繼續走,第一步要處理的就是按照我們需要的格式創建模塊,我定義了一個對象 module:
let module = {
_raw: rootModule,
_state: rootModule.state,
_children: {}
}
如上雖然定義了模塊信息但是還沒有進行存儲起來,所以我們的第二步就是保存模塊信息。
首先我將根模塊進行存儲起來,子模塊我們稍后再說。
// 2.保存模塊信息
if (arr.length === 0) {
// 保存根模塊
this.root = module;
} else {
// 保存子模塊
}
注意一下我所說的內容,我只是將根模塊進行存儲起來,子模塊還沒有進行存儲起來。
好,到這里我們的第二部先告一段落,接下來我們就來看下第三步怎么做。
第三步就是處理子模塊,我們先來看下怎么處理子模塊。
首先我們要知道子模塊的名字,這個可以通過循環根模塊的 modules 屬性來獲取。知道了子模塊的名稱之后,我們就可以通過子模塊的名稱來獲取子模塊的數據。從根模塊的 modules 屬性當中通過子模塊的名稱來獲取子模塊的數據。
隨后我們就可以通過子模塊的數據來創建子模塊的模塊信息,然后將子模塊的模塊信息進行存儲起來。
我們先將第三步的內容完成,代碼如下:
for (let childrenModuleName in rootModule.modules) {
let childrenModule = rootModule.modules[childrenModuleName];
this.register(arr.concat(childrenModuleName), childrenModule)
}
如上代碼的含義是,首先通過 for in 循環遍歷根模塊的 modules 屬性,然后通過子模塊的名稱來獲取子模塊的數據,然后通過子模塊的數據來創建子模塊的模塊信息,然后將子模塊的模塊信息進行存儲起來。
這里就直接遞歸調用 register 方法,將子模塊的名稱和子模塊的數據傳遞進去。并且在遞歸調用的時候,將子模塊的名稱添加到 arr 數組當中。目的就是為了區分是根模塊還是子模塊。也是為了方便我們后續的操作(保存子模塊)。
好了到這里我們的第三步也完成了,我們先將 arr 數組進行打印,看下 arr 數組的內容是什么。
??注意:記得將官方的 Vuex 注釋掉,用我們自己的不然你會發現打印的內容和我們自己的不一樣。
打印結果如下圖:
[] 代表的是根模塊,[home] 代表的是 home 模塊,[account] 代表的是 account 模塊,[account, login] 代表的是 account 模塊下的 login 模塊。
好了到這里我們的第三步也完成了,接下來我們就來看下之前第二步沒有完成的內容怎么完成。
基于第三步的打印結果分析出來各個模塊的關系就可以根據這個關系得出各個模塊的父子關系。按照這個關系就可以將子模塊的模塊信息進行存儲起來。
我們先來看下代碼怎么寫,其實非常簡單我們先來分析一下,只需要分析 [account, login] 這種情況即可,我還是先將這種場景先不直接就給出答案,我們循序漸進的來,我們就走普通的邏輯,然后再來看下代碼怎么寫。我會直接往根模塊的 children 屬性當中添加子模塊的模塊信息。子模塊信息已經通過參數傳遞進來了,所以說我只需要將子模塊的名稱獲取到即可,根據之前打印的結果來看,子模塊的名稱是 arr 數組當中的最后一個元素,所以說我只需要獲取 arr 數組當中的最后一個元素即可。
然后將子模塊的名稱作為 key,子模塊的模塊信息作為 value,添加到根模塊的 children 屬性當中即可。
代碼如下:
this.root._children[arr[arr.length - 1]] = module;
好了到這里我們的第二步也完成了,我們高高興興的要去打印結果了,結果如下:
發現 login 模塊在 root 的 children 屬性當中了,login 模塊應該在 account 模塊的 children 屬性當中,所以說我們的代碼還是有問題的。
誒,我們的代碼有問題,那么我們就來看下問題出在哪里了。
問題出在我們不能直接往根模塊的 children 屬性當中添加子模塊的模塊信息,我們應該往父模塊的 children 屬性當中添加子模塊的模塊信息。
那么我們怎么知道父模塊是誰呢?我們可以通過 root._children 來得到父模塊,然后將子模塊的模塊信息添加到父模塊的 children 屬性當中即可。
代碼如下:
let parent = arr.splice(0, arr.length - 1).reduce((root, currentKey) => {
return root._children[currentKey];
}, this.root);
parent._children[arr[arr.length - 1]] = module;
讓我來逐步解釋:
-
let parent = arr.splice(0, arr.length - 1):這一行代碼從數組arr中移除并返回除了最后一個元素之外的所有元素,將這些元素存儲在parent變量中。 -
.reduce((root, currentKey) => { return root._children[currentKey]; }, this.root):這是一個reduce函數調用,它逐個遍歷parent數組中的元素。root是累積的結果,初始值是this.root。currentKey是每次迭代中的當前元素。 -
parent._children[arr[arr.length - 1]] = module:最后一行代碼將module賦值給parent對象的_children屬性中的某個屬性,該屬性的名稱來自數組arr的最后一個元素。
如上是個簡單的解釋,接下來我套用數據來解釋一下,如下:
例如有這么一個父子結構模塊的數組 let testArr = ['account', 'login'];,那么 arr.splice(0, arr.length - 1) 就是將 testArr 數組中的最后一個元素移除并返回除了最后一個元素之外的所有元素,將這些元素存儲在 parent 變量中,那么 parent 變量中的值就是 ['account']。
然后 reduce 函數調用,它逐個遍歷 parent 數組中的元素。root 是累積的結果,初始值是 this.root。currentKey 是每次迭代中的當前元素。那么 root._children[currentKey] 就是 this.root._children['account'],那么 this.root._children['account'] 的值就是 account 模塊的模塊信息。
最后一行代碼將 module 賦值給 parent 對象的 _children 屬性中的某個屬性,該屬性的名稱來自數組 arr 的最后一個元素。那么 parent._children[arr[arr.length - 1]] 就是 account 模塊的模塊信息,然后將 module 賦值給 account 模塊的子模塊,這樣我們的 login 模塊就在 account 模塊的 children 屬性當中了。
這個時候我們在來打印一下結果,結果如下:
好了這回就是我們想要的結果了,到此為止我們的 ModuleCollection 類就完成了。
總結
以上是生活随笔為你收集整理的手撕Vuex-提取模块信息的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一文搞懂双链表
- 下一篇: 开发一个现代化的.NetCore控制台程