成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

vuex源碼分析(一)

keithyau / 2807人閱讀

摘要:的源碼分析系列大概會(huì)分為三篇博客來(lái)講,為什么分三篇呢,因?yàn)閷?xiě)一篇太多了。這段代碼檢測(cè)是否存在,如果不存在那么就調(diào)用方法這行代碼用于確保在我們實(shí)例化之前,已經(jīng)存在。每一個(gè)集合也是的實(shí)例。

vuex的源碼分析系列大概會(huì)分為三篇博客來(lái)講,為什么分三篇呢,因?yàn)閷?xiě)一篇太多了。您看著費(fèi)勁,我寫(xiě)著也累

這是vuex的目錄圖

分析vuex的源碼,我們先從index入口文件進(jìn)行分析,入口文件在src/store.js文件中

export default {
 // 主要代碼,狀態(tài)存儲(chǔ)類(lèi)
  Store,
  // 插件安裝
  install,
  // 版本
  version: "__VERSION__",
  mapState,
  mapMutations,
  mapGetters,
  mapActions,
  createNamespacedHelpers
}

一個(gè)一個(gè)來(lái)看Store是vuex提供的狀態(tài)存儲(chǔ)類(lèi),通常我們使用Vuex就是通過(guò)創(chuàng)建Store的實(shí)例,
install方法是配合Vue.use方法進(jìn)行使用,install方法是用來(lái)編寫(xiě)Vue插件的通用公式,先來(lái)看一下代碼

export function install (_Vue) {
  if (Vue && _Vue === Vue) {
    if (process.env.NODE_ENV !== "production") {
      console.error(
        "[vuex] already installed. Vue.use(Vuex) should be called only once."
      )
    }
    return
  }
  Vue = _Vue
  applyMixin(Vue)
}

這個(gè)方法的作用是什么呢:當(dāng)window上有Vue對(duì)象的時(shí)候,就會(huì)手動(dòng)編寫(xiě)install方法,并且傳入Vue的使用。
在install中法中有applyMixin這個(gè)函數(shù),這個(gè)函數(shù)來(lái)自云src/mixin.js,下面是mixin.js的代碼

export default function (Vue) {
// 判斷VUe的版本
  const version = Number(Vue.version.split(".")[0])
// 如果vue的版本大于2,那么beforeCreate之前vuex進(jìn)行初始化
  if (version >= 2) {
    Vue.mixin({ beforeCreate: vuexInit })
  } else {
    // override init and inject vuex init procedure
    // for 1.x backwards compatibility.
    // 兼容vue 1的版本
    const _init = Vue.prototype._init
    Vue.prototype._init = function (options = {}) {
      options.init = options.init
        ? [vuexInit].concat(options.init)
        : vuexInit
      _init.call(this, options)
    }
  }

  /**
   * Vuex init hook, injected into each instances init hooks list.
   */

// 給vue的實(shí)例注冊(cè)一個(gè)$store的屬性,類(lèi)似咱們使用vue.$route
  function vuexInit () {
    const options = this.$options
    // store injection
    if (options.store) {
      this.$store = typeof options.store === "function"
        ? options.store()
        : options.store
    } else if (options.parent && options.parent.$store) {
      this.$store = options.parent.$store
    }
  }
}

這段代碼的總體意思就是就是在vue的聲明周期中進(jìn)行vuex的初始化,并且對(duì)vue的各種版本進(jìn)行了兼容。vuexInit就是對(duì)vuex的初始化。為什么我們能在使用vue.$store這種方法呢,因?yàn)樵趘uexInit中為vue的實(shí)例添加了$store屬性
Store構(gòu)造函數(shù)
先看constructor構(gòu)造函數(shù)

constructor (options = {}) {
    // Auto install if it is not done yet and `window` has `Vue`.
    // To allow users to avoid auto-installation in some cases,
    // this code should be placed here. See #731
    // 判斷window.vue是否存在,如果不存在那么就安裝
    if (!Vue && typeof window !== "undefined" && window.Vue) {
      install(window.Vue)
    }
// 這個(gè)是在開(kāi)發(fā)過(guò)程中的一些環(huán)節(jié)判斷,vuex要求在創(chuàng)建vuex 
// store實(shí)例之前必須先使用這個(gè)方法Vue.use(Vuex),并且判斷promise是否可以使用
    if (process.env.NODE_ENV !== "production") {
      assert(Vue, `must call Vue.use(Vuex) before creating a store instance.`)
      assert(typeof Promise !== "undefined", `vuex requires a Promise polyfill in this browser.`)
      assert(this instanceof Store, `Store must be called with the new operator.`)
    }
    // 提取參數(shù)
    const {
      plugins = [],
      strict = false
    } = options

    let {
      state = {}
    } = options
    if (typeof state === "function") {
      state = state() || {}
    }

    // store internal state
    // 初始化store內(nèi)部狀態(tài),Obejct.create(null)是ES5的一種方法,Object.create(
    // object)object是你要繼承的對(duì)象,如果是null,那么就是創(chuàng)建一個(gè)純凈的對(duì)象
    this._committing = false 
    this._actions = Object.create(null)
    this._actionSubscribers = []
    this._mutations = Object.create(null)
    this._wrappedGetters = Object.create(null)
    this._modules = new ModuleCollection(options)
    this._modulesNamespaceMap = Object.create(null)
    this._subscribers = []
    this._watcherVM = new Vue()

    // bind commit and dispatch to self
    const store = this
    const { dispatch, commit } = this
    // 定義dispatch方法
    this.dispatch = function boundDispatch (type, payload) {
      return dispatch.call(store, type, payload)
    }
    // 定義commit方法
    this.commit = function boundCommit (type, payload, options) {
      return commit.call(store, type, payload, options)
    }

    // strict mode
    // 嚴(yán)格模式
    this.strict = strict

    // init root module.
    // this also recursively registers all sub-modules
    // and collects all module getters inside this._wrappedGetters
    // 初始化根模塊,遞歸注冊(cè)所有的子模塊,收集getters
    installModule(this, state, [], this._modules.root)

    // initialize the store vm, which is responsible for the reactivity
    // (also registers _wrappedGetters as computed properties)
    // 重置vm狀態(tài),同時(shí)將getters轉(zhuǎn)換為computed計(jì)算屬性
    resetStoreVM(this, state)

    // apply plugins
    // 執(zhí)行每個(gè)插件里邊的函數(shù)
    plugins.forEach(plugin => plugin(this))

    if (Vue.config.devtools) {
      devtoolPlugin(this)
    }
  }

因?yàn)関uex是由es6進(jìn)行編寫(xiě)的,我真覺(jué)得es6的模塊簡(jiǎn)直是神器,我以前就納悶了像Echarts這種8萬(wàn)行的庫(kù),他們是怎么寫(xiě)出來(lái)的,上次還看到一個(gè)應(yīng)聘百度的問(wèn)Echarts的源碼沒(méi)有??膳?!后來(lái)才知道模塊化。如今es6引入了import這種模塊化語(yǔ)句,讓我們編寫(xiě)龐大的代碼變得更加簡(jiǎn)單了。

if (!Vue && typeof window !== "undefined" && window.Vue) {
      install(window.Vue)
    }

這段代碼檢測(cè)window.Vue是否存在,如果不存在那么就調(diào)用install方法

assert(Vue, `must call Vue.use(Vuex) before creating a store instance.`)

這行代碼用于確保在我們實(shí)例化 Store之前,vue已經(jīng)存在。

assert(typeof Promise !== "undefined", `vuex requires a Promise polyfill in this browser.`)

這一行代碼用于檢測(cè)是否支持Promise,因?yàn)関uex中使用了Promise,Promise是es6的語(yǔ)法,但是有的瀏覽器并不支持es6所以我們需要在package.json中加入babel-polyfill用來(lái)支持es6
下面來(lái)看接下來(lái)的代碼

const {
      plugins = [],
      strict = false
    } = options

這利用了es6的解構(gòu)賦值拿到options中的plugins。es6的解構(gòu)賦值在我的《前端面試之ES6》中講過(guò),大致就是[a,b,c] = [1,2,3] 等同于a=1,b=2,c=3。后面一句的代碼類(lèi)似取到state的值。

this._committing = false 
this._actions = Object.create(null)
this._actionSubscribers = []
this._mutations = Object.create(null)
this._wrappedGetters = Object.create(null)
this._modules = new ModuleCollection(options)
this._modulesNamespaceMap = Object.create(null)
this._subscribers = []
this._watcherVM = new Vue()

這里主要用于創(chuàng)建一些內(nèi)部的屬性,為什么要加_這是用于辨別屬性,_就表示內(nèi)部屬性,我們?cè)谕獠空{(diào)用這些屬性的時(shí)候,就需要小心。

this._committing 標(biāo)志一個(gè)提交狀態(tài)
this._actions 用來(lái)存儲(chǔ)用戶定義的所有actions
this._actionSubscribers 
this._mutations 用來(lái)存儲(chǔ)用戶定義所有的 mutatins
this._wrappedGetters 用來(lái)存儲(chǔ)用戶定義的所有 getters 
this._modules 
this._subscribers 用來(lái)存儲(chǔ)所有對(duì) mutation 變化的訂閱者
this._watcherVM 是一個(gè) Vue 對(duì)象的實(shí)例,主要是利用 Vue 實(shí)例方法 $watch 來(lái)觀測(cè)變化的
commit和dispatch方法在過(guò)后再講

installModule(this, state, [], options)
是將我們的options傳入的各種屬性模塊注冊(cè)和安裝
resetStoreVM(this, state)
resetStoreVM 方法是初始化 store._vm,觀測(cè) state 和 getters 的變化;最后是應(yīng)用傳入的插件
下面是installModule的實(shí)現(xiàn)

function installModule (store, rootState, path, module, hot) {

  const isRoot = !path.length
  const namespace = store._modules.getNamespace(path)

  // register in namespace map
  if (module.namespaced) {
    store._modulesNamespaceMap[namespace] = module
  }

  // set state
  if (!isRoot && !hot) {
    const parentState = getNestedState(rootState, path.slice(0, -1))
    const moduleName = path[path.length - 1]
    store._withCommit(() => {
      Vue.set(parentState, moduleName, module.state)
    })
  }

  const local = module.context = makeLocalContext(store, namespace, path)

  module.forEachMutation((mutation, key) => {
    const namespacedType = namespace + key
    registerMutation(store, namespacedType, mutation, local)
  })

  module.forEachAction((action, key) => {
    const type = action.root ? key : namespace + key
    const handler = action.handler || action
    registerAction(store, type, handler, local)
  })

  module.forEachGetter((getter, key) => {
    const namespacedType = namespace + key
    registerGetter(store, namespacedType, getter, local)
  })

  module.forEachChild((child, key) => {
    installModule(store, rootState, path.concat(key), child, hot)
  })
}

這個(gè)函數(shù)的主要作用是什么呢:初始化組件樹(shù)根組件、注冊(cè)所有子組件,并將所有的getters存儲(chǔ)到this._wrapperdGetters屬性中
這個(gè)函數(shù)接受5個(gè)函數(shù),store, rootState, path, module, hot。我們來(lái)看看他們分別代表什么:
store: 表示當(dāng)前Store實(shí)例
rootState: 表示根state,
path: 其他的參數(shù)的含義都比較好理解,那么這個(gè)path是如何理解的呢。我們可以將一個(gè)store實(shí)例看成module的集合。每一個(gè)集合也是store的實(shí)例。那么path就可以想象成一種層級(jí)關(guān)系,當(dāng)你有了rootState和path后,就可以在Path路徑中找到local State。然后每次getters或者setters改變的就是localState
module:表示當(dāng)前安裝的模塊
hot:當(dāng)動(dòng)態(tài)改變modules或者熱更新的時(shí)候?yàn)閠rue

 const isRoot = !path.length
 const namespace = store._modules.getNamespace(path)

用于通過(guò)Path的長(zhǎng)度來(lái)判斷是否為根,下面那一句是用與注冊(cè)命名空間

  module.forEachMutation((mutation, key) => {
    const namespacedType = namespace + key
    registerMutation(store, namespacedType, mutation, local)
  })

這句是將mutation注冊(cè)到模塊上,后面幾句是同樣的效果,就不做一一的解釋了

  module.forEachChild((child, key) => {
    installModule(store, rootState, path.concat(key), child, hot)
  })

這兒是通過(guò)遍歷Modules,遞歸調(diào)用installModule安裝模塊。
if (!isRoot && !hot) {

const parentState = getNestedState(rootState, path.slice(0, -1))
const moduleName = path[path.length - 1]
store._withCommit(() => {
  Vue.set(parentState, moduleName, module.state)
})

}
這段用于判斷如果不是根并且Hot為false的情況,將要執(zhí)行的俄操作,這兒有一個(gè)函數(shù)getNestedState (state, path),函數(shù)的內(nèi)容如下:

  function getNestedState (state, path) {
    return path.length
       ? path.reduce((state, key) => state[key], state)
       : state
}

這個(gè)函數(shù)的意思拿到該module父級(jí)的state,拿到其所在的moduleName,然后調(diào)用store._withCommit()方法

store._withCommit(() => {
      Vue.set(parentState, moduleName, module.state)
})

把當(dāng)前模塊的state添加到parentState,我們使用了_withCommit()方法,_withCommit的方法我們留到commit方法再講。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/89428.html

相關(guān)文章

  • vuex源碼分析

    摘要:的源碼分析系列大概會(huì)分為三篇博客來(lái)講,為什么分三篇呢,因?yàn)閷?xiě)一篇太多了。這段代碼檢測(cè)是否存在,如果不存在那么就調(diào)用方法這行代碼用于確保在我們實(shí)例化之前,已經(jīng)存在。每一個(gè)集合也是的實(shí)例。 vuex的源碼分析系列大概會(huì)分為三篇博客來(lái)講,為什么分三篇呢,因?yàn)閷?xiě)一篇太多了。您看著費(fèi)勁,我寫(xiě)著也累showImg(https://segmentfault.com/img/bVXKqD?w=357&...

    BDEEFE 評(píng)論0 收藏0
  • [源碼學(xué)習(xí)] Vuex

    摘要:為了更清楚的理解它的原理和實(shí)現(xiàn),還是從源碼開(kāi)始讀起吧。結(jié)構(gòu)梳理先拋開(kāi),的主要源碼一共有三個(gè)文件,,初始化相關(guān)用到了和我們使用創(chuàng)建的實(shí)例并傳遞給的根組件。這個(gè)方法的第一個(gè)參數(shù)是構(gòu)造器。的中,在保證單次調(diào)用的情況下,調(diào)用對(duì)構(gòu)造器進(jìn)入了注入。 原文鏈接 Vuex 作為 Vue 官方的狀態(tài)管理架構(gòu),借鑒了 Flux 的設(shè)計(jì)思想,在大型應(yīng)用中可以理清應(yīng)用狀態(tài)管理的邏輯。為了更清楚的理解它的原理和...

    FreeZinG 評(píng)論0 收藏0
  • Vuex源碼學(xué)習(xí)()功能梳理

    摘要:我們通常稱(chēng)之為狀態(tài)管理模式,用于解決組件間通信的以及多組件共享狀態(tài)等問(wèn)題。創(chuàng)建指定命名空間的輔助函數(shù),總結(jié)的功能首先分為兩大類(lèi)自己的實(shí)例使用為組件中使用便利而提供的輔助函數(shù)自己內(nèi)部對(duì)數(shù)據(jù)狀態(tài)有兩種功能修改數(shù)據(jù)狀態(tài)異步同步。 what is Vuex ? 這句話我想每個(gè)搜索過(guò)Vuex官網(wǎng)文檔的人都看到過(guò), 在學(xué)習(xí)源碼前,當(dāng)然要有一些前提條件了。 了解Vuex的作用,以及他的使用場(chǎng)景。 ...

    livem 評(píng)論0 收藏0
  • vuex源碼閱讀分析

    摘要:繼續(xù)看后面的首先遍歷的,通過(guò)和首先獲取然后調(diào)用方法,我們來(lái)看看是不是感覺(jué)這個(gè)函數(shù)有些熟悉,表示當(dāng)前實(shí)例,表示類(lèi)型,表示執(zhí)行的回調(diào)函數(shù),表示本地化后的一個(gè)變量。必須是一個(gè)函數(shù),如果返回的值發(fā)生了變化,那么就調(diào)用回調(diào)函數(shù)。 這幾天忙啊,有絕地求生要上分,英雄聯(lián)盟新賽季需要上分,就懶著什么也沒(méi)寫(xiě),很慚愧。這個(gè)vuex,vue-router,vue的源碼我半個(gè)月前就看的差不多了,但是懶,哈哈。...

    gplane 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<