通俗易懂Vuex源碼導讀2.1-installModule模塊安裝及內容建立

installModule(模塊安裝函數)

  • 參數介紹html

    • store:store 對象實例,new Vuex.Store({...})生成的對象
    • rootState:根模塊的state對象
    • path:上一章節介紹過的,當前模塊所處層級數組
    • module:模塊對象
    • hot:暫時用不上,先不介紹
  • 判斷當前模塊是否根模塊

    圖片

  • 獲取模塊的命名空間vue

    • 調用狀態模塊樹的 getNamespace 方法,傳入當前模塊的模塊層級數組 path
    • getNamespace 和以前提到的 get 方法相似,一樣是從根模塊出發,根據給出的路徑數組,遞歸每個層級的模塊

      圖片

    • 在每個模塊中,判斷是否設置命名空間變量namespaced
    • 有命名空間,則以模塊名結合"/",造成命名空間路徑,即本函數是獲取模塊的命名空間前綴,如對應下圖,moduleC的命名空間前綴爲'moduleA/moduleC/',其中moduleB並無設置命名空間vuex

      {
        moduleA:{
          namespaced:true,
          modules:{
            moduleB:{
                namespaced:false,
                modules:{
                  moduleC:{
                    namespaced:true,
                  }
                }
              }
          }
        }
      }
    • 有些同窗可能會疑惑,module對象裏面,沒有定義namespaced變量啊?其實namespaced是經過 get攔截器定義的,獲取namespaced時,真正獲取的是this._rawModule.namespaced,即module對象保存的配置信息中namespaced的值

      圖片

  • 若是當前模塊設置了命名空間,則將本模塊存入當模塊命名容器對象_modulesNamespaceMap中,並以剛剛生成的命名空間前綴名爲key。注意,若是當前模塊沒有設置命名空間,即便父模塊設置了,也不須要加入到_modulesNamespaceMap中,例如moduleB不會被加入到_modulesNamespaceMap中

    圖片

  • 對於非根模塊segmentfault

    • 經過getNestedState,尋找父模塊的 state對象。api

      • getNestedState參數介紹,rootState是根容器的state,path.slice(0, -1)是除去本模塊後的模塊層級數組
      • 與get函數、getNamespace函數相似,從state中根據path層級數組,每層遞歸尋找,找到對應的state,在這裏找的是父模塊的state對象
      • 從這個操做,咱們能夠猜想,state也將和module模塊樹同樣,經過state造成一個state樹,其樹結構和module結構相對應
    • 獲取本模塊的模塊名
    • 調用store的_withCommit函數數組

      • 該函數的操做很簡單,只是將設置_committing標識符爲ture,而後執行某函數,函數執行完在將_committing設置爲原來的值
      • 即容許在函數函數執行期間,修改state的值
      • _committing標識符在介紹全局變量時介紹過,用於在嚴格模式時,防止非commit方式修改state

        圖片

    • 在_withCommit函數中數據結構

      • 借用Vue的set方法,Vue 在install中被傳入並保存
      • 往父State對象中,添加以模塊名爲key,爲模塊內state對象爲value的變量,借用Vue.set方法,實現數據響應
      • 注意,因爲是直接往父模塊的State中添加變量,當父模塊的state中有與插入的模塊同名的變量時,state中變量將被覆蓋。

        圖片

    • 結合 Vue.set(parentState, moduleName, module.state) 及 getNestedState函數,咱們能夠肯定state也和module模塊樹同樣,經過state造成一個state樹,其樹結構和module結構相同。
    • 這就是爲何獲取子模塊的state變量時,是經過this.$store.state.moduleName.xxx來獲取,對應官網
  • 建立模塊內容,makeLocalContext(store, namespace, path)。並將生成的content內容放在module.content中。咱們跳轉這裏,看看makeLocalContext具體操做app

    • 模塊內容,返回命名空間前綴處理後的getters,state,commit,dispatch方法
  • 調用module.forEachMutation方法,對模塊的mutation方法進行註冊ide

    圖片

    • registerMutation註冊函數函數

      • 參數介紹,store是store實例, type是mutation函數名, handler是mutation的函數體,即實際執行的函數, local是剛剛生成的模塊的local對象
      • store._mutations[type],以mutation函數名爲key,在store根實例的_mutations容器對象中,添數組容器。存放全部同名的mutation函數
      • 因此mutation是不怕重名的,重名將逐個執行調用。這個在官網中沒有作介紹
      • 往mutation函數數組中加入一個函數,函數的參數就是咱們在使用commit時的第二個參數,載荷參數
      • 在函數內部,修改this,並傳入local對象做爲參數,這也是爲何咱們在commit的時候只傳遞了負載參數,但在實際執行mutation的時候還能夠接收到本模塊的state參數
      • 總的來講,收集了配置函數中的mutation函數,統一經過store實例的_mutations變量保存
        圖片
  • 調用module.forEachAction方法,對模塊的action進行註冊

    • 註冊action的操做和註冊Mutation的操做大致相同,一樣是經過一個變量收集全部模塊的action函數
    • 只是註冊action時,多傳遞些參數

      圖片

  • 調用registerGetter,註冊每個getter方法,經過_wrappedGetters收集

    圖片

  • 最後是循環註冊全部模塊
  • 小結,總的來講,是收集模塊配置文件中的每個mutation項,每個action,每個getter。往回調函數中添加參數

    圖片

makeLocalContext,建立模塊內容

  • 參數介紹

    • store, store 對象實例
    • namespace, 模塊的命名空間前綴,無論本模塊是否設置命名空間,父模塊設置了,也會該值
    • path,模塊層級關係數組,注意,namespace與path並不必定相同,由於命名層級,只有當模塊設置有命名空間,才存在對應層級命名
  • 定義local對象

    • 定義local對象的dispatch函數

      • 根據namespace(本模塊及祖先容器是不是設置過命名空間)進行判斷
      • 沒有設置,則直接使用 Store實例的 dispatch函數
      • 有命名空間,則在使用 Store 實例的dispatch函數前,對參數進行一些處理

        • 統一參數形式 unifyObjectStyle,type是調用dispatch方法的一個參數,即action函數名,payload是負載變量,options是配置項。unifyObjectStyle函數的原理就是,判斷參數是否爲對象,是對象則進行解析,並調整參數位置
        • 根據options.root判斷是否往全局發送的action函數,對應官網
      • 若是不是發送全局的action函數,即只發送本模塊內的action函數,這是往調用的的 action函數名中,添加命名空間路徑前綴。例如對應下圖,actionC函數在_actions中,則被保存爲'/moduleA/moduleC/actionC'(具體保存過程將在後續介紹到)。在調用時,使用方法爲this.$store.dispatch('/moduleA/moduleC/actionC')。對應官網介紹
      {
        moduleA:{
          namespaced:true,
          modules:{
            moduleB:{
                namespaced:false,
                modules:{
                  moduleC:{
                    namespaced:true,
                     actions: {
                        actionC (context) {...}
                      }
                  }
                }
              }
          }
        }
      }
      • 最後,調用store實例的dispatch函數

        圖片

    • 定義commit函數

      • 與定義dispatch函數相似,有命名空間,則往mutation函數前添加命名空間前綴
      • 最後也而是調用store實例的commit函數

        圖片

  • 調用Object.defineProperties函數,往local對象中添加兩個變量getters和state,設置local對象的getter和state

    圖片

    • Object.defineProperties函數用於往某對象中添加屬性,並設置該數據的訪問攔截器,即訪問該數據時,將先調用攔截器函數,defineProperties函數詳細介紹
    • 定義getters變量,並設置其攔截器。一樣的,判斷是否有命名空間前綴

      • 沒有,則直接訪問store 對象實例的getters變量
      • 不然調用makeLocalGetters函數,生成本身的getters

        • 參數介紹,store是 store 對象實例,namespace是命名空間前綴
        • 先定義一個對象 gettersProxy,譯爲 getters代理
        • 遍歷store.getters中的全部函數,(store.getters變量暫時還未定義到,其指向 store的_wrappedGetters,getter函數容器)

          • 檢測各個函數名,判斷該函數名的前綴是否與模塊的命名空間前綴相同。找到即符合命名前綴的函數。
          • 去除命名空間前綴,能獲取純粹的getter函數名
          • 一樣,經過Object.defineProperty,往剛剛定義的gettersProxy對象中,添加變量,並設置其get攔截器。enumerable是其中一個配置項目,設置當使用for等枚舉循環時,是否顯示該變量
          • 以帶命名空間前綴的getter名爲key,添加到gettersProxy對象中,當訪問它時,返回是,從Store.getters(即store._wrappedGetters,getter容器)中提取的帶上命名空間前綴的getter函數
          • 因此說,其實全部的getter都存放在了Store實例的_wrappedGetters變量中,如模塊沒有命名空間前綴,則直接存入。不然將getter函數名帶上命名空間前綴後,再加入進去
        • 小結,

          • makeLocalGetters的做用,是將經過模塊拿getter時,如何經過store.getters中取。是否應該添加前綴、
    • 定義state,及其攔截器

      • state的獲取,則不須要命名空間前綴的識別,並且直接經過getNestedState,從state樹結構中取
      • 這是由於state和getter的存儲方式不同,state是獨立的狀態樹,有明顯的層級關係
      • getters則所有都放在store實例的getters變量中保存,屬於同層級,只是經過函數前綴進行了區分(有設命名空間的話)
      • state是根據層級關係設置,getters則更具命名空間區分,與層級關係不大
        圖片
  • 小結

    • 定義可local變量,有設置命名空間,則往各個函數名中添加命名空間前綴
    • 對應數據結構中,全局容器的介紹就更清晰了,實際操做的函數仍是那個函數,這裏只是在調用函數前,對參數進行一些調整
    • 設置了getters,state,commit,dispatch方法的中間處理
  • 啊,一口氣看無缺累,歇歇
    圖片

總目錄

相關文章
相關標籤/搜索