原文連接vue
Vuex 做爲 Vue 官方的狀態管理架構,借鑑了 Flux 的設計思想,在大型應用中能夠理清應用狀態管理的邏輯。爲了更清楚的理解它的原理和實現,仍是從源碼開始讀起吧。總共 1000 多行的代碼,讀起來也相對輕鬆。vuex
cloc src/ ------------------------------------------------------------------ Language files blank comment code ------------------------------------------------------------------ JavaScript 5 53 141 389 ------------------------------------------------------------------ SUM: 5 53 141 389 ------------------------------------------------------------------ cloc test/ ------------------------------------------------------------------ Language files blank comment code ------------------------------------------------------------------ JavaScript 5 62 30 793 ------------------------------------------------------------------ SUM: 5 62 30 793 ------------------------------------------------------------------
先拋開 middlewares,Vuex 的主要源碼一共有三個文件:shell
file | intro |
---|---|
index.js | Class Store, install,... |
override.js | 初始化 Vuex |
util.js | 相關 util(用到了 getWatcher 和 getDeep) |
咱們使用 Store
建立 Vuex 的實例並傳遞給 Vue 的根組件。主要包含了 state
和 mutation
。Store
建立了一個 data
爲 state
的 Vue 實例,使用了 ES6 Class 的 get
和 set
對 state 作了映射,對 state 的從新 set 固然是不容許的,get 則映射到了 this._vm._data
。緩存
Store
提供了 dispatch
方法來完成對 state 的修改,和想象中的差很少,在 _mutations 裏找到對應 type
的 mutation,參數併入 this.state
傳參調用。架構
做爲一個 Vue 的插件,Vuex 須要被這樣引入:ide
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex)
Vue 的插件應當有一個公開方法 install
。這個方法的第一個參數是 Vue 構造器。 Vuex 的 install
中,在保證單次調用的狀況下,調用 override
對 Vue 構造器進入了注入。函數
override
中對 Vue.prototype._init
注入了 vuexInit
,vuexInit
會在每一個 instance 的 init hook 中調用。this
第一步是綁定 store
, Vuex 會尋找 options 中的 store
做爲實例的 $store
,在不存在時則以遞歸的方式尋找父組件中的 $store
,所以在 Vuex 的項目中,store
只須要在根組件中注入便可。spa
第二步是處理 vuex
, 分別處理其中的 getters
和 actions
, 以 example/counter/Counter.vue
爲例:prototype
Vuex 用 Object.defineProperty
爲每一個 getter 在 vm 上綁定了 data,特別的是 getter 做爲單向僅 get 數據流,並不能被 set,因此對應的 setter
爲報錯用的空函數。而 getter
的原理相似於 computed getter
,特別的是使用了 store
的 uniqueId 爲標識作了緩存,這樣同一個 getter 在全部組件中都會使用相同的 watcher。
Action 相對要簡單一些,以 $store
做爲 action 第一個參數,並將 action 綁定在 instance 上。造成了一個閉環,讓 action 訪問到 store。
Vuex 源碼上粗略的分析基本就到這裏了,其實不少地方的代碼都很值得細細研究,好比 Store 中的 middlewares 能夠完成一些神奇的事情,這裏就不一一分析了,畫了一張圖,按源碼的思路大概表達下數據流的意思。O(∩_∩)O
+-----------+ | | | Store +>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+ | | v |-----------| v | state <<<<<<+ v |-----------| ^ v +>>>>>- distapatch ->>>>+ v ^ +-----------+ v ^ v ^ +--------------------+ v ^ | | v ^ | Component | v ^ | | v ^ |--------------------| v ^ +<<<<<----- $store <------<<<<<+ ^ v |--------------------| ^ v | vuex: { | ^ v | | ^ +>>>>>----- getters: {}, | ^ | | +<<<<<<<<<<<<<<<<<<<<<<<<<<----- actions: {} | | | | } | +--------------------+