最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談Vuex注入Vue生命周期的過程

 更新時(shí)間:2019年05月20日 10:49:28   作者:小生方勤  
這篇文章主要介紹了Vuex 注入 Vue 生命周期的過程,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

這篇文章是【前端詞典】系列文章的第 13 篇文章,接下的 9 篇我會(huì)圍繞著 Vue 展開,希望這 9 篇文章可以使大家加深對(duì) Vue 的了解。當(dāng)然這些文章的前提是默認(rèn)你對(duì) Vue 有一定的基礎(chǔ)。如果一點(diǎn)基礎(chǔ)都沒有,建議先看官方文檔。

第一篇文章我會(huì)結(jié)合 Vue 和 Vuex 的部分源碼,來說明 Vuex 注入 Vue 生命周期的過程。

說到源碼,其實(shí)沒有想象的那么難。也和我們平時(shí)寫業(yè)務(wù)代碼差不多,都是方法的調(diào)用。但是源碼的調(diào)用樹會(huì)復(fù)雜很多。

為何使用 Vuex

使用 Vue 我們就不可避免的會(huì)遇到組件間共享的數(shù)據(jù)或狀態(tài)。應(yīng)用的業(yè)務(wù)代碼逐漸復(fù)雜,props、事件、事件總線等通信的方式的弊端就會(huì)愈發(fā)明顯。這個(gè)時(shí)候我們就需要 Vuex 。Vuex 是一個(gè)專門為 Vue 設(shè)計(jì)的狀態(tài)管理工具。

狀態(tài)管理是 Vue 組件解耦的重要手段。

它借鑒了 Flux、redux 的基本思想,將狀態(tài)抽離到全局,形成一個(gè) Store。

 Vuex 不限制你的代碼結(jié)構(gòu),但需要遵守一些規(guī)則:

  • 應(yīng)用層級(jí)的狀態(tài)應(yīng)該集中到單個(gè) store 對(duì)象中
  • 提交 mutation 是更改狀態(tài)的唯一方法,并且這個(gè)過程是同步的
  • 異步邏輯都應(yīng)該封裝到 action 里面

 Vuex 注入 Vue 生命周期的過程

我們?cè)诎惭b插件的時(shí)候,總會(huì)像下面一樣用 Vue.use() 來載入插件,可是 Vue.use() 做了什么呢?

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

Vue.use() 做了什么

安裝 Vue.js 插件。如果插件是一個(gè)對(duì)象,必須提供 install 方法。如果插件是一個(gè)函數(shù),它會(huì)被作為 install 方法。install 方法調(diào)用時(shí),會(huì)將 Vue 作為參數(shù)傳入。

以上是官方文檔的解釋。

接下來我們從源碼部分來看看 Vue.use() 都做了什么。

Vue 源碼在 initGlobalAPI 入口方法中調(diào)用了 initUse (Vue) 方法,這個(gè)方法定義了 Vue.use() 需要做的內(nèi)容。

function initGlobalAPI (Vue) {
 ......
 initUse(Vue);
 initMixin$1(Vue); // 下面講 Vue.mixin 會(huì)提到
 ......
}

function initUse (Vue) {
 Vue.use = function (plugin) {
 var installedPlugins = (this._installedPlugins || (this._installedPlugins = []));
 /* 判斷過這個(gè)插件是否已經(jīng)安裝 */
 if (installedPlugins.indexOf(plugin) > -1) {
 return this
 }
 var args = toArray(arguments, 1);
 args.unshift(this);
 /* 判斷插件是否有 install 方法 */
 if (typeof plugin.install === 'function') {
 plugin.install.apply(plugin, args);
 } else if (typeof plugin === 'function') {
 plugin.apply(null, args);
 }
 installedPlugins.push(plugin);
 return this
 };
}

這段代碼主要做了兩件事情:

  1. 一件是防止重復(fù)安裝相同的 plugin
  2. 另一件是初始化 plugin

插件的 install 方法

看完以上源碼,我們知道插件(Vuex)需要提供一個(gè) install 方法。那么我們看看 Vuex 源碼中是否有這個(gè)方法。結(jié)果當(dāng)然是有的:

/* 暴露給外部的 install 方法 */
function install (_Vue) {
 /* 避免重復(fù)安裝(Vue.use 內(nèi)部也會(huì)檢測(cè)一次是否重復(fù)安裝同一個(gè)插件)*/
 if (Vue && _Vue === Vue) {
 {
 console.error(
 '[vuex] already installed. Vue.use(Vuex) should be called only once.'
 );
 }
 return
 }
 Vue = _Vue;
 /* 將 vuexInit 混淆進(jìn) Vue 的 beforeCreate(Vue2.0) 或 _init 方法(Vue1.0) */
 applyMixin(Vue);
}

這段代碼主要做了兩件事情:

  1. 一件是防止 Vuex 被重復(fù)安裝
  2. 另一件是執(zhí)行 applyMixin ,目的是執(zhí)行 vuexInit 方法初始化 Vuex

接下來 我們看看 applyMixin(Vue) 源碼:

/* 將 vuexInit 混淆進(jìn) Vue 的 beforeCreate */
function applyMixin (Vue) {
 var version = Number(Vue.version.split('.')[0]);
 if (version >= 2) {
 Vue.mixin({ beforeCreate: vuexInit });
 } else {
 /* Vue1.0 的處理邏輯,此處省略 */
 ......
 }
 function vuexInit () {
 ......
 }
}

從上面的源碼,可以看出 Vue.mixin 方法將 vuexInit 方法混淆進(jìn) beforeCreate 鉤子中,也是因?yàn)檫@個(gè)操作,所以每一個(gè) vm 實(shí)例都會(huì)調(diào)用 vuexInit 方法。那么 vuexInit 又做了什么呢?

vuexInit()

我們?cè)谑褂?Vuex 的時(shí)候,需要將 store 傳入到 Vue 實(shí)例中去。

new Vue({
 el: '#app',
 store
});

但是我們卻在每一個(gè) vm 中都可以訪問該 store,這個(gè)就需要靠 vuexInit 了。

 function vuexInit () {
 const options = this.$options
 if (options.store) {
 /* 根節(jié)點(diǎn)存在 stroe 時(shí) */
 this.$store = typeof options.store === 'function'
 ? options.store()
 : options.store
 } else if (options.parent && options.parent.$store) {
 /* 子組件直接從父組件中獲取 $store,這樣就保證了所有組件都公用了全局的同一份 store*/
 this.$store = options.parent.$store
 }
 }

根節(jié)點(diǎn)存在 stroe 時(shí),則直接將 options.store 賦值給 this.$store 。否則則說明不是根節(jié)點(diǎn),從父節(jié)點(diǎn)的 $store 中獲取。

通過這步的操作,我們就以在任意一個(gè) vm 中通過 this.$store 來訪問 Store 的實(shí)例。接下來我們反過來說說 Vue.mixin()。

Vue.mixin()

全局注冊(cè)一個(gè)混入,影響注冊(cè)之后所有創(chuàng)建的每個(gè) Vue 實(shí)例。插件作者可以使用混入,向組件注入自定義的行為。 不推薦在應(yīng)用代碼中使用。

在 vue 的 initGlobalAPI 入口方法中調(diào)用了 initMixin$1(Vue) 方法:

function initMixin$1 (Vue) {
 Vue.mixin = function (mixin) {
 this.options = mergeOptions(this.options, mixin);
 return this
 };
}

Vuex 注入 Vue 生命周期的過程大概就是這樣,如果你感興趣的話,你可以直接看看 Vuex 的源碼,接下來我們說說 Store。

Store

上面我們講到了 vuexInit 會(huì)從 options 中獲取 Store。所以接下來會(huì)講到 Store 是怎么來的呢?

我們使用 Vuex 的時(shí)候都會(huì)定義一個(gè)和下面類似的 Store 實(shí)例。

import Vue from 'vue'
import Vuex from 'vuex'
import mutations from './mutations'

Vue.use(Vuex)

const state = {
 showState: 0,    
}

export default new Vuex.Store({
 strict: true,
	state,
	getters,
})

不要在發(fā)布環(huán)境下啟用嚴(yán)格模式。嚴(yán)格模式會(huì)深度監(jiān)測(cè)狀態(tài)樹來檢測(cè)不合規(guī)的狀態(tài)變更 —— 請(qǐng)確保在發(fā)布環(huán)境下關(guān)閉嚴(yán)格模式,以避免性能損失。

state 的響應(yīng)式

你是否關(guān)心 state 是如何能夠響應(yīng)式呢?這個(gè)主要是通過 Store 的構(gòu)造函數(shù)中調(diào)用的 resetStoreVM(this, state) 方法來實(shí)現(xiàn)的。

這個(gè)方法主要是重置一個(gè)私有的 _vm(一個(gè) Vue 的實(shí)例) 對(duì)象。這個(gè) _vm 對(duì)象會(huì)保留我們的 state 樹,以及用計(jì)算屬性的方式存儲(chǔ)了 store 的 getters?,F(xiàn)在具體看看它的實(shí)現(xiàn)過程。

/* 使用 Vue 內(nèi)部的響應(yīng)式注冊(cè) state */
function resetStoreVM (store, state, hot) {
 /* 存放之前的vm對(duì)象 */
 const oldVm = store._vm 

 store.getters = {}
 const wrappedGetters = store._wrappedGetters
 const computed = {}

 /* 通過 Object.defineProperty 方法為 store.getters 定義了 get 方法。當(dāng)在組件中調(diào)用 this.$store.getters.xxx 這個(gè)方法的時(shí)候,會(huì)訪問 store._vm[xxx]*/
 forEachValue(wrappedGetters, (fn, key) => {
 computed[key] = partial(fn, store)
 Object.defineProperty(store.getters, key, {
 get: () => store._vm[key],
 enumerable: true // for local getters
 })
 })

 const silent = Vue.config.silent
 /* 設(shè)置 silent 為 true 的目的是為了取消 _vm 的所有日志和警告 */
 Vue.config.silent = true
 /* 這里new了一個(gè)Vue對(duì)象,運(yùn)用Vue內(nèi)部的響應(yīng)式實(shí)現(xiàn)注冊(cè)state以及computed*/
 store._vm = new Vue({
 data: {
 $$state: state
 },
 computed
 })
 Vue.config.silent = silent

 /* 使能嚴(yán)格模式,Vuex 中對(duì) state 的修改只能在 mutation 的回調(diào)函數(shù)里 */
 if (store.strict) {
 enableStrictMode(store)
 }

 if (oldVm) {
 /* 解除舊 vm 的 state 的引用,并銷毀這個(gè)舊的 _vm 對(duì)象 */
 if (hot) {
 store._withCommit(() => {
 oldVm._data.$$state = null
 })
 }
 Vue.nextTick(() => oldVm.$destroy())
 }
}

state 的響應(yīng)式大概就是這樣實(shí)現(xiàn)的,也就是初始化 resetStoreVM 方法的過程。

看看 Store 的 commit 方法

我們知道 commit 方法是用來觸發(fā) mutation 的。

commit (_type, _payload, _options) {
 /* unifyObjectStyle 方法校參 */
 const {
 type,
 payload,
 options
 } = unifyObjectStyle(_type, _payload, _options)

 const mutation = { type, payload }
 /* 找到相應(yīng)的 mutation 方法 */
 const entry = this._mutations[type]
 if (!entry) {
 if (process.env.NODE_ENV !== 'production') {
 console.error(`[vuex] unknown mutation type: ${type}`)
 }
 return
 }
 /* 執(zhí)行 mutation 中的方法 */
 this._withCommit(() => {
 entry.forEach(function commitIterator (handler) {
 handler(payload)
 })
 })
 /* 通知所有訂閱者,傳入當(dāng)前的 mutation 對(duì)象和當(dāng)前的 state */
 this._subscribers.forEach(sub => sub(mutation, this.state))

 if (
 process.env.NODE_ENV !== 'production' &&
 options && options.silent
 ) {
 console.warn(
 `[vuex] mutation type: ${type}. Silent option has been removed. ` +
 'Use the filter functionality in the vue-devtools'
 )
 }
}

該方法先進(jìn)行參數(shù)風(fēng)格校驗(yàn),然后利用 _withCommit 方法執(zhí)行本次批量觸發(fā) mutation 處理函數(shù)。執(zhí)行完成后,通知所有 _subscribers (訂閱函數(shù))本次操作的 mutation 對(duì)象以及當(dāng)前的 state 狀態(tài)。

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論

新郑市| 库尔勒市| 浙江省| 收藏| 沂水县| 嘉禾县| 瑞丽市| 永德县| 黑水县| 武陟县| 白城市| 石狮市| 青田县| 山西省| 米林县| 宁远县| 甘谷县| 新兴县| 灵石县| 宿州市| 视频| 莱阳市| 崇礼县| 鹤壁市| 万宁市| 乌什县| 阜阳市| 乌拉特后旗| 南丹县| 黔江区| 明水县| 荃湾区| 房山区| 日土县| 临城县| 将乐县| 富锦市| 常熟市| 射洪县| 博客| 衡南县|