日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > vue >内容正文

vue

从vuex源码分析module与namespaced

發(fā)布時間:2024/9/21 vue 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从vuex源码分析module与namespaced 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

使用vue已經(jīng)有半年有余, 在各種正式非正式項目中用過, 開始專注于業(yè)務(wù)比較多, 用到現(xiàn)在也遇見不少因為理解不深導(dǎo)致的問題. 有問題就有找原因的勇氣, 所以帶著問題搞一波.

帶著問題看源碼

所以來整理了一下使用過程中不注意或者不規(guī)范, 或者簡化寫法的奇技淫巧, 會結(jié)合文檔的說明和實際的問題來看看源碼, 問題:

  • module在vuex里實際的數(shù)據(jù)結(jié)構(gòu)
  • namespaced在vuex里實際的數(shù)據(jù)結(jié)構(gòu)
  • mapState, mapActions等helper的正確用法(配合module/namespaced), 或者是否存在更多騷用法
  • mutation中賦值/觸發(fā)state變化原理

源碼分析

看的源碼版本為vuex2.3.1

我們使用vuex可能是類似:

import Vue from 'vue' import Vuex from 'vuex' import plugins from './plugins' Vue.use(Vuex) export default new Vuex.Store({state: {todo: ["todo1", "todo2"]},mutations: {mutationName(state, payload) {state.xxx = payload.xxx}},actions: {actionName({ commit, dispatch }, payload) {commit(mutationName, payload)}},modules: {catagories: {state: {},mutations: {}}},plugins })

使用vuex的方法為使用Vue.use來installvuex, 并new一個Store實例, 我們來看一下vuex核心對象.

Store對象分析

line6: 本地vue變量, 在install時會被賦值, 之后會通過vue是否為undefined來判斷是否install

Store對象構(gòu)建

line10~14: 判斷vuex是否被正確使用
line16~26: 獲取options, state可以和vue的component的data一樣為函數(shù)return一個對象, 會在這段代碼中被parse
line28~36: store對象內(nèi)部變量初始化
line39~46: 綁定commit和dispatch方法到自身
line54: 裝載動作
line58: 裝載響應(yīng)動作
line61: 調(diào)用插件

store內(nèi)部變量初始化

this._committing = false

是否合法更新state的標(biāo)識, 對象有方法_withCommit是唯一可以改動_committing的方法, 只有對象內(nèi)部使用_withCommit更新狀態(tài)才是合法的, 在strict模式下非法更新state會拋出異常.

this._modules = new ModuleCollection(options)

modules的cache, 直接把store的參數(shù)全部扔給了ModuleCollection新建一個modules對象.

點擊跳轉(zhuǎn)ModuleCollection對象來看分析.

this._modulesNamespaceMap = Object.create(null) this._subscribers = [] this._watcherVM = new Vue()

其余的變量是新建了空的變量, 之后會在install模塊的時候賦值.

綁定dispatch和commit方法

在line39~46, 對dispatch和commit方法進(jìn)行綁定, 使dispatch方法可以調(diào)用在Store對象上注冊過的._actions

和._mutations的方法.

dispatch方法在line108, 先兼容了參數(shù)的寫法, 取到參數(shù), 然后判斷Store對象的_.actions屬性是否注冊過, 如果注冊過多個, 將會依次調(diào)用. 也就是如果type重復(fù)了也是會調(diào)用多次的, 這個地方如果出錯debug會非常困難. 暫時沒有理解vuex此處設(shè)計的意圖.

commit方法稍微多一點, 大體思路是一樣的, 只是直接執(zhí)行沒有返回值, dispatch會返回執(zhí)行結(jié)果. 另外在line95進(jìn)行了subscriber的操作, 我們暫且不知道subscriber的作用. 稍后再看.

install模塊

首先來看參數(shù):

function installModule (store, rootState, path, module, hot) // 調(diào)用 installModule(this, state, [], this._modules.root)

line255 根據(jù)path獲得namespace, 做法是讀取path的每個模塊, 如果namespaced為true則拼接, 例如path為['catagories', 'price', 'detail'], 其中price的namespaced為false, 其余為true, 那么獲得的namespace為catagories/detail/.

line258~260 把namespaced為true的module注冊到_modulesNamespaceMap.

line271的makeLocalContext函數(shù)整理了namespace和type的關(guān)系. 在之后的三個module.forEachXxx中, 都調(diào)用了registerXxx, 最后的參數(shù)都是makeLocalContext的返回值. 我們來分析一下makeLocalContext的作用:

被注冊到全局的mutation/actiongetter實際的type類似于namespace1/namespace2/type的形式, 而我們在namespaced為true的module中調(diào)用的type只是:type. 所以在namespace[true]的action中調(diào)用的所有dispatch, commit, getter, state 都會被加上 path.join("/") + "/" 的type來調(diào)用到正確的方法.

根據(jù)注冊的type, 我還得到了一個偏門結(jié)論: 可以通過設(shè)置type為namespace1/namespace2/type來調(diào)用其他namespace的type(待測試), 因為他們是這樣被注冊的.

install child module

通過比較, install child module的時候是改了第三第四個參數(shù): path => path.concat(key), module => module.getChild(key).

主要區(qū)別只是在line264~268, 與ModuleCollection的遞歸注冊子module行為類似, 遞歸的path參數(shù)流程上只是多了一步把當(dāng)前l(fā)oop產(chǎn)生的對象掛到父節(jié)點上. 做法也是一樣的, 把module名字(path)作為key, 套在父級state上. 也就是結(jié)構(gòu)為:

state: {...currentState,moduleName: {...subState},module2Name: {...anotherSubState} }

在之前注冊Mutation的時候vuex也是通過這個方法來試mutation獲得嵌套過的state作為arguments[0]的.

Store對象總結(jié)

store對象把傳入的options放入了各個變量進(jìn)行儲存, 并提供了commit, dispatch等方法來調(diào)用和處理他們:

._modules

這里存放raw的modules, 未經(jīng)處理的, 以module名字作為key的方式遞歸子module.

.state

這里也是以module名字作為key的方式遞歸儲存?zhèn)魅氲膕tate

entrys

這里的entry指._actions, ._mutations, ._getters. 他們的儲存方式并沒有遞歸儲存key, 而是平級的, 用/來分割namespace來分辨type, 并在注冊時把當(dāng)前的entry綁定對應(yīng)的state(通過getNestedState方法).

問題: 如果在不同module注冊了相同type的mutation, 會發(fā)生什么?

回答: 會依次在自己的state中執(zhí)行, 不會影響對方state, 但是會造成錯誤執(zhí)行. (待測試). 所以應(yīng)該在大的項目中盡量使用namespaced[true]的方式, 而不是命名的方式.(但是也是可以利用/來串namespace的, 所以自己type命名避免/)

._modulesNamespaceMap

根據(jù)namespace為key來存放子module

初始化Store VM

這里會新建一個Vue實例并賦值給Store對象的._vm屬性, 把整個vuex的狀態(tài)放進(jìn)去. 并判斷嚴(yán)格模式, 如果為嚴(yán)格模式會在非法改變狀態(tài)的時候拋出異常.

這樣整個構(gòu)建動作已經(jīng)完成了, 那么這個._vm在什么時候用的, 請看下面的章節(jié).

Store對象的屬性&方法

line64 state的getter方法, 會獲取._vm的vue實例的state. 所以我們在vue代碼中this.$store.state.xxx獲取到的東西就是這個vue的實例的數(shù)據(jù).

line68 當(dāng)直接set Store的state時報錯, 只能通過設(shè)置._vm來進(jìn)行.

剩余的方法的是vuex的進(jìn)階用法, 是可以在使用時對vuex狀態(tài)進(jìn)行操作的方法, 詳見文檔

ModuleCollection對象

我們來看下ModuleCollection的構(gòu)造方法.

register根module

調(diào)用了register方法, 把參數(shù)的path設(shè)為根目錄, runtime設(shè)為false.

register方法一開始(l30)就判斷了除state外的屬性的值是否為函數(shù), 若不是則拋出異常.

line33 把module參數(shù)(還是初始的options, 就是{state:{...}, mutations:{...}, actions: {...}}這個)和runtime = false 來構(gòu)建了Module對象(稍后我們看Module對象的構(gòu)造)

line35 把ModuleCollection的root私有變量設(shè)為了剛才使用初始o(jì)ptions新建的Module對象.

line42 如果初始o(jì)ptions有modules這個屬性, 就開始遞歸注冊modules.

遞歸register子module

上面是register的第一個參數(shù)path為空, 也就是root節(jié)點的時候的流程, 在最后一部分(line42)根據(jù)是否當(dāng)前注冊的module含有modules屬性來遞歸注冊, 這部分我們來看一下register的path參數(shù)的行為會把數(shù)據(jù)存成什么結(jié)構(gòu). 以概覽部分的例子的參數(shù)為例(modules含有一個key為catagories)來走一遍代碼流程. (開始~)

被作為子module傳入register方法的參數(shù)應(yīng)該為: path(['catagories']), rawModule(state: {},mutations: {}), runtime(false).

注意到的是, 如果catagories有同級module, 被傳入的path也是一個元素的數(shù)組, 也就是path的意思應(yīng)該類似于從跟到當(dāng)前module的層級, 對于兄弟節(jié)點是無感的.

這里的runtime尚未明白用途, 可能是在別處調(diào)用的. 注冊流程應(yīng)該runtime都為false.

一路看下來, 也是new了一個Module對象, 但是沒有走到line35把new出的對象放到root變量里, 而是在line37~38去尋找當(dāng)前module的父節(jié)點并把自己作為child, append到父節(jié)點上.

這里又腦補了一下數(shù)據(jù)結(jié)構(gòu): path.slice(0, -1)是獲取被pop()一下的path, path[path.lengt - 1]是獲取當(dāng)前path的最后一個元素, 也就是當(dāng)前正在被register的module的key. 所以之前對于path的數(shù)據(jù)結(jié)構(gòu)判斷是正確的.

這里的appendChild和getChild很明顯是Module對象的方法了, 我們再繼續(xù)看Module對象的結(jié)構(gòu).

Module對象

最后來看Module對象的構(gòu)造~

接受2個參數(shù), 一個rawModule, 一個runtime, 第一個參數(shù)是剛才相對于key為catagories的value, 也就是類似{state: xxx, mutations: xxx, actions: xxx}的options.

Module的構(gòu)造函數(shù)只是把參數(shù)拆分, 放入了自己的私有變量, 其中state也接受函數(shù), 并執(zhí)行函數(shù)parse成對象存入私有變量. 其他變量都是原封不動儲存的, 所以vuex給他起名為 rawModule 吧. 剩下那些方法都是顧名思義的, 語法上也簡單, 沒什么好看的.

總結(jié)

那么這樣Store對象的._modules屬性的數(shù)據(jù)結(jié)構(gòu)已經(jīng)很清楚了. 類似于(腦內(nèi)):

{// (ModuleCOllection實例)root: {// (Module實例)_rawModule: {state: {...}, mutations: {...}, // ...(全是options直接傳入)},state: {}, // 進(jìn)行過parse的state, 如果是function會調(diào)用并賦值_children: {catagories: {// (Module實例)},anotherModule: {// (Module實例), 遞歸}}} }

總結(jié)一點, 就是這里貯存的數(shù)據(jù)都是"raw"的.

helpers

所有的helper都用了兩個wrap方法, 先來看下這兩個方法的作用.

normalizeNamespace

因為helper是都接受兩種傳參方式:mapState(namespace, map) / mapState(map) , 如果第一個參數(shù)為map時這個函數(shù)把namespace設(shè)為空字符串 , 并且檢查namespace的最后一個字符是不是/, 如果不是的話加上.

normalizeMap

我們map的內(nèi)容也接受兩種語法:

["state1","state2" ]

或者是

{state1: state => state.state1,state2: state => state.state2 }

這個wrap函數(shù)會把兩種形式都normalize為含有key和val屬性的數(shù)組, 便于統(tǒng)一處理. 也就是上面?zhèn)€兩個形式會轉(zhuǎn)化為:

// Array like [{key: "state1",val: "state1" }, {key: "state2",val: "state2" }] // Object like [{key: "state1",val: state => state.state1 }, {key: "state2",val: state => state.state2 }]

mapState

這里做了2個處理:

  • 如果namespace不為空, 把state和getter的環(huán)境切換到相對于namespace的環(huán)境(就是之前的makeLocalContext的返回值)
  • 如果val為函數(shù)則執(zhí)行, 否則返回state的val為鍵的屬性. 兩者的執(zhí)行環(huán)境皆為處理過namespace的local環(huán)境.

mapActions

mapAction的val語法只接受字符串的, 所以先把val前借namespace, 變?yōu)? namespace/val, 這樣能符合在Store里注冊的entry名.

然后檢查了一下namespace是否被注冊過, 也就是防碰撞, 然后把val作為type, 并把剩余參數(shù)帶著dispatch Store里的action.


參考:

  • 美團vuex源碼分析

總結(jié)

以上是生活随笔為你收集整理的从vuex源码分析module与namespaced的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 偷拍老头老太高潮抽搐 | 永久免费看mv网站入口亚洲 | 7777久久亚洲中文字幕 | 91丨国产丨捆绑调教 | 国产麻豆一区二区 | 五月婷av| 亚洲狼人综合网 | av在线资源网站 | 福利片网址 | 天天操中文字幕 | 日韩av免费播放 | 一区二区三区久久久久 | 免看一级片 | 无码人妻aⅴ一区二区三区69岛 | 永久看看免费大片 | 完全免费在线视频 | 黄色av免费在线 | 黄色一级一片免费播放 | 欧美激情黑人 | 污片免费看 | 久久精品视频免费 | 这里有精品视频 | 成人7777 | 搡国产老太xxx网站 高h喷汁呻吟3p | 一级片少妇 | 国产视频一区二区三区在线观看 | 人妖天堂狠狠ts人妖天堂狠狠 | 久久久欧美精品sm网站 | 日韩免费精品 | 肉大捧一进一出免费视频 | 97人人爽 | 日韩黄页网站 | 在线观看一二三区 | 天天操天天干视频 | 日日噜噜夜夜爽爽 | 老司机午夜免费福利 | 毛片av免费看| 欧美黄色一级大片 | 女人下面无遮挡 | 亚洲欧美精品一区二区 | 国产精品久久国产 | 国产精品亚洲成在人线 | 国产全是老熟女太爽了 | 一级肉体全黄毛片 | 久草热在线观看 | 欧美日韩在线观看视频 | 欧美不卡影院 | 婷婷综合六月 | 黄色裸体视频 | 亚洲性综合 | 国产一区在线免费观看 | www毛片| 伦理片一区二区三区 | 美女极度色诱图片www视频 | 91九色国产ts另类人妖 | 先锋影音av在线资源 | 国产三级播放 | 在线免费看mv的网站入口 | youjizz亚洲| 色吧久久 | 国产六区 | 日本丰满熟妇bbxbbxhd | 精品一区在线观看视频 | 怡红院精品视频 | 日韩欧美一区视频 | 黄色xxxxxx| 免费公开在线视频 | 私人网站 | 精品无码久久久久成人漫画 | 精品国产一区二区在线观看 | 羞羞涩涩网站 | 国产 日韩 欧美 精品 | 青娱乐毛片 | 国产经典毛片 | 天天拍天天射 | 好吊视频一区 | 欧美日韩视频在线 | 成人自拍视频网站 | 青青国产在线视频 | 免费色网| 久久国产色av免费观看 | 久久精品无码Av中文字幕 | 国产www视频| 国产18页 | 亚洲精品久久久久久 | 被各种性器调教到哭vk | 国产欧美视频在线观看 | av在线免费播放网站 | 国产又粗又大又长 | 亚洲欧美国产一区二区三区 | 污视频网站在线播放 | av无码一区二区三区 | 国产aⅴ无码片毛片一级一区2 | 男人疯狂高潮呻吟视频 | 高清性爱视频 | 美女福利在线视频 | 亚洲在线国产 | 黄色小说视频网站 | 久久久视频在线 |