? ? ? ? Vuex是一個專為Vue服務(wù)情龄,用于管理頁面數(shù)據(jù)狀態(tài)、提供統(tǒng)一數(shù)據(jù)操作的生態(tài)系統(tǒng)。它集中于MVC模式中的Model層弟灼,規(guī)定所有的數(shù)據(jù)操作必須通過 action – mutation – state change 的流程來進行爬凑,再結(jié)合Vue的數(shù)據(jù)視圖雙向綁定特性來實現(xiàn)頁面的展示更新困乒。統(tǒng)一的頁面狀態(tài)管理以及操作處理,可以讓復(fù)雜的組件交互變得簡單清晰贰谣,同時可在調(diào)試模式下進行時光機般的倒退前進操作娜搂,查看數(shù)據(jù)改變過程,使code debug更加方便吱抚。
最近在開發(fā)的項目中用到了Vuex來管理整體頁面狀態(tài)百宇,遇到了很多問題。決定研究下源碼秘豹,在答疑解惑之外携御,能深入學(xué)習(xí)其實現(xiàn)原理。
先將問題拋出來既绕,使學(xué)習(xí)和研究更有針對性:
使用Vuex只需執(zhí)行 Vue.use(Vuex)啄刹,并在Vue的配置中傳入一個store對象的示例,store是如何實現(xiàn)注入的凄贩?
state內(nèi)部是如何實現(xiàn)支持模塊配置和模塊嵌套的誓军?
在執(zhí)行dispatch觸發(fā)action(commit同理)的時候,只需傳入(type, payload)疲扎,action執(zhí)行函數(shù)中第一個參數(shù)store從哪里獲取的昵时?
如何區(qū)分state是外部直接修改,還是通過mutation方法修改的椒丧?
調(diào)試時的“時空穿梭”功能是如何實現(xiàn)的壹甥?
注:本文對有Vuex有實際使用經(jīng)驗的同學(xué)幫助更大,能更清晰理解Vuex的工作流程和原理壶熏,使用起來更得心應(yīng)手句柠。初次接觸的同學(xué),可以先參考Vuex官方文檔進行基礎(chǔ)概念的學(xué)習(xí)。
一溯职、框架核心流程
進行源碼分析之前管怠,先了解一下官方文檔中提供的核心思想圖,它也代表著整個Vuex框架的運行流程缸榄。
如圖示渤弛,Vuex為Vue Components建立起了一個完整的生態(tài)圈,包括開發(fā)中的API調(diào)用一環(huán)甚带。圍繞這個生態(tài)圈她肯,簡要介紹一下各模塊在核心流程中的主要功能:
1、Vue Components:Vue組件鹰贵。HTML頁面上晴氨,負責(zé)接收用戶操作等交互行為,執(zhí)行dispatch方法觸發(fā)對應(yīng)action進行回應(yīng)碉输。
2籽前、dispatch:操作行為觸發(fā)方法,是唯一能執(zhí)行action的方法敷钾。
3枝哄、actions:操作行為處理模塊。負責(zé)處理Vue Components接收到的所有交互行為阻荒。包含同步/異步操作挠锥,支持多個同名方法,按照注冊的順序依次觸發(fā)侨赡。向后臺API請求的操作就在這個模塊中進行蓖租,包括觸發(fā)其他action以及提交mutation的操作。該模塊提供了Promise的封裝羊壹,以支持action的鏈式觸發(fā)蓖宦。
4、commit:狀態(tài)改變提交操作方法油猫。對mutation進行提交稠茂,是唯一能執(zhí)行mutation的方法。
5眨攘、mutations:狀態(tài)改變操作方法主慰。是Vuex修改state的唯一推薦方法嚣州,其他修改方式在嚴格模式下將會報錯鲫售。該方法只能進行同步操作,且方法名只能全局唯一该肴。操作之中會有一些hook暴露出來情竹,以進行state的監(jiān)控等。
6匀哄、state:頁面狀態(tài)管理容器對象秦效。集中存儲Vue components中data對象的零散數(shù)據(jù)雏蛮,全局唯一,以進行統(tǒng)一的狀態(tài)管理阱州。頁面顯示所需的數(shù)據(jù)從該對象中進行讀取挑秉,利用Vue的細粒度數(shù)據(jù)響應(yīng)機制來進行高效的狀態(tài)更新。
7苔货、getters:state對象讀取方法犀概。圖中沒有單獨列出該模塊,應(yīng)該被包含在了render中夜惭,Vue Components通過該方法讀取全局state對象姻灶。
Vue組件接收交互行為,調(diào)用dispatch方法觸發(fā)action相關(guān)處理诈茧,若頁面狀態(tài)需要改變产喉,則調(diào)用commit方法提交mutation修改state,通過getters獲取到state新值敢会,重新渲染Vue Components曾沈,界面隨之更新。
二鸥昏、目錄結(jié)構(gòu)介紹
打開Vuex項目晦譬,看下源碼目錄結(jié)構(gòu)。
Vuex提供了非常強大的狀態(tài)管理功能互广,源碼代碼量卻不多敛腌,目錄結(jié)構(gòu)劃分也很清晰。先大體介紹下各個目錄文件的功能:
Ⅰ惫皱、module:提供module對象與module對象樹的創(chuàng)建功能像樊;
Ⅱ、plugins:提供開發(fā)輔助插件旅敷,如“時光穿梭”功能生棍,state修改的日志記錄功能等;
Ⅲ媳谁、helpers.js:提供action涂滴、mutations以及getters的查找API;
Ⅳ晴音、index.js:是源碼主入口文件柔纵,提供store的各module構(gòu)建安裝;
Ⅴ锤躁、mixin.js:提供了store在Vue實例上的裝載注入搁料;
Ⅵ、util.js:提供了工具方法如find、deepCopy郭计、forEachValue以及assert等方法霸琴。
三、初始化裝載與注入
先看個簡單的例子:
store.js文件中昭伸,加載Vuex框架梧乘,創(chuàng)建并導(dǎo)出一個空配置的store對象實例。
然后在index.js中庐杨,正常初始化一個頁面根級別的Vue組件宋下,傳入這個自定義的store對象。
如問題1所述辑莫,以上實例除了Vue的初始化代碼学歧,只是多了一個store對象的傳入。一起看下源碼中的實現(xiàn)方式各吨。
3.2 裝載分析
index.js文件代碼執(zhí)行開頭枝笨,定義局部 Vue 變量,用于判斷是否已經(jīng)裝載和減少全局作用域查找揭蜒。
然后判斷若處于瀏覽器環(huán)境下且加載過Vue横浑,則執(zhí)行install方法。
install方法將Vuex裝載到Vue對象上屉更,Vue.use(Vuex) 也是通過它執(zhí)行徙融,先看下Vue.use方法實現(xiàn):
若是首次加載,將局部Vue變量賦值為全局的Vue對象瑰谜,并執(zhí)行applyMixin方法欺冀,install實現(xiàn)如下:
來看下applyMixin方法內(nèi)部代碼。如果是2.x.x以上版本萨脑,可以使用 hook 的形式進行注入隐轩,或使用封裝并替換Vue對象原型的_init方法,實現(xiàn)注入渤早。
具體實現(xiàn):將初始化Vue根組件時傳入的store設(shè)置到this對象的$store屬性上职车,子組件從其父組件引用$store屬性,層層嵌套進行設(shè)置鹊杖。在任意組件中執(zhí)行 this.$store 都能找到裝載的那個store對象悴灵,vuexInit方法實現(xiàn)如下:
看個圖例理解下store的傳遞。
頁面Vue結(jié)構(gòu)圖:
對應(yīng)store流向:
四骂蓖、store對象構(gòu)造
上面對Vuex框架的裝載以及注入自定義store對象進行分析积瞒,解決了問題1。接下來詳細分析store對象的內(nèi)部功能和具體實現(xiàn)涯竟,來解答為什么actions赡鲜、getters空厌、mutations中能從arguments[0]中拿到store的相關(guān)數(shù)據(jù)?等問題庐船。
store對象實現(xiàn)邏輯比較復(fù)雜银酬,先看下構(gòu)造方法的整體邏輯流程來幫助后面的理解:
原文出處:美團點評技術(shù)團隊