我看Vuex(一)

以前閱讀過 redux 的源碼,vuex 一樣也是一個狀態管理工具,以前開發 vue 應用的時候,用到的 vuex 也比較多,因此天然對 vuex 很有興趣,最主要的緣由是 我愛學習,(很差意思,臉掉地上了),,哈哈哈哈哈哈 javascript

images

(其實過年這幾天也挺無聊的。。。vue

接下來咱們來回歸正題 java

default

Vuex 是如何引入到 Vue 中的

咱們都知道,在 Vue 中使用 Vuex 必須經過 Vue.use(Vuex) 方法來使用,因此先來瞄一瞄 Vue 對 Vuex 作了什麼不可告人的事,驚恐.gifreact

來到 vue 源碼下的 core/global-api/use.jsgit

Vue.use = function (plugin: Function | Object) {
        // 檢測該插件是否已經被安裝
        if (plugin.installed) {
            return
        }
        // use 支持傳入一個選項對象,如
        // Vue.use(MyPlugin, { someOption: true })
        const args = toArray(arguments, 1)  //獲取可選對象
        
        args.unshift(this)  // 將Vue 構造器傳入,當插件的第一個參數
        if (typeof plugin.install === 'function') {
            // install執行插件安裝
            plugin.install.apply(plugin, args)
        } else if (typeof plugin === 'function') {
            plugin.apply(null, args)
        }
        plugin.installed = true  // 防止再次安裝
        return this
    }
複製代碼

因此,vue 對插件仍是挺溫柔的,只用了它的一個安裝函數進行插件的安裝。好,咱們來看看 vuex 的 install 函數 在 store.js 的最下面,咱們看到了它的身影github

function install(_Vue) {
  if (Vue && _Vue === Vue) {
    // 給出警告:說明重複安裝
    return
  }
  Vue = _Vue
  applyMixin(Vue)
}
複製代碼

這裏咱們也能夠看到 vuex 本身內部也作了一個限制,防止重複安裝,最後該函數調用了 applyMixin(Vue)vuex

咻一下,咱們來到 mixin.js,該函數也很簡單,先是獲取 Vue 的版本號,若是版本是 2.0 以上版本,就使用 Vue.mixin 來在全部組件中混入 beforeCreate 生命鉤子,對應的處理函數是 vuexInit,反之就向後兼容 1.x 版本redux

function vuexInit() {
        // this -> vm
        const options = this.$options
        // store injection
        if (options.store) { // 獲取傳入new Vue({store}) 裏面的 store,並註冊爲 vm 的 $store 屬性,這樣咱們就能在實例中使用 this.$store 訪問 store 對象了
            this.$store = typeof options.store === 'function' ?
                options.store() :
                options.store
        } else if (options.parent && options.parent.$store) {
            // 子組件從其父組件引用 $store 屬性
            this.$store = options.parent.$store
        }
    }
複製代碼

至此,前菜已經上齊了api

主角 Store 閃亮登場

835ab1e97a

store.js,別看長長一竄,有500多行,其實看進去了,你會感受,也沒啥可怕嘛 該文件主要由一個 Store 類和一些輔助函數構成,咱們先來看 這個構造類瀏覽器

該構造函數中首先是進行一些必要的判斷,如瀏覽器環境下自動安裝、是否已經安裝了 Vue、是否支持 Promise,是否已經實例化了 Store 構造函數,其中用到了 assert 斷言函數

// 構造函數
    constructor(options = {}) {
        // .......
    }

// util.js
   function assert (condition, msg) {
    if (!condition) throw new Error(`[vuex] ${msg}`)
  }
複製代碼

而後是從傳入的options 中提取出 pluginsstrict,並作一些變量的初始化

// store internal state
    // 表示提交狀態,做用是保證對 Vuex 中 state 的修改只能在 mutation 的回調函數中,而不能在外部隨意修改state
    this._committing = false
    // 用戶定義的 actions
    this._actions = Object.create(null)
    // action 訂閱者
    this._actionSubscribers = []
    // // 用戶定義的 mutations
    this._mutations = Object.create(null)
    // 用戶定義的 getters
    this._wrappedGetters = Object.create(null)
    // 收集用戶定義的 modules
    this._modules = new ModuleCollection(options)
    // 模塊命名空間map
    this._modulesNamespaceMap = Object.create(null)
    // 存儲全部對 mutation 變化的訂閱者,當執行commit時會執行隊列中的函數
    this._subscribers = []
    // 建立一個 Vue 實例, 利用 $watch 監測 store 數據的變化
    this._watcherVM = new Vue()
複製代碼

接着後面是對 dispatch 和 commit 函數中的 this 的從新綁定

const store = this
    const {
      dispatch,
      commit
    } = this

    this.dispatch = function boundDispatch(type, payload) {
      return dispatch.call(store, type, payload)
    }
    this.commit = function boundCommit(type, payload, options) {
      return commit.call(store, type, payload, options)
    }
複製代碼

這樣作是由於在組件中經過 this.$store 直接調用 dispatch/commit 方法時, 可以使 dispatch/commit 方法中的 this 指向當前的 store 對象而不是當前組件的 this。
咱們知道 new Vue 時會把傳入的對象的中的 this 綁定爲 vm,例如 computed 屬性,裏面咱們寫以下代碼時,會把計算屬性裏面的 this 綁定爲當前的 vm 實例

computed: {
    // 計算屬性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 實例
      return this.message.split('').reverse().join('')
    }
  }
複製代碼

( 上面這段若有不妥,歡迎指出,謝謝 ^_^

接着就是 安裝模塊,vm 組件設置,傳入插件以及 devtoolPlugin 插件的設置了

this.strict = strict

    const state = this._modules.root.state

    // init root module.
    // this also recursively registers all sub-modules
    // and collects all module getters inside this._wrappedGetters
    installModule(this, state, [], this._modules.root)

    // initialize the store vm, which is responsible for the reactivity
    // (also registers _wrappedGetters as computed properties)
    resetStoreVM(this, state)

    // apply plugins
    plugins.forEach(plugin => plugin(this))

    if (Vue.config.devtools) {
      devtoolPlugin(this)
    }
複製代碼

接下來咱們先不講 dispatchcommit 是怎麼實現的,先來重點關注下 modules 這部分,畢竟前面已經 new ModuleCollection(options),先來後到嘛,,哈哈

因爲如今的篇幅也算能夠了,怕你們看到長篇大論頭疼,因此咱們轉移陣地。

1

(若有不當,歡迎指出,謝謝 ^_^

原文地址: 我看Vuex(一)

相關文章
相關標籤/搜索