欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue中的情侶屬性$dispatch和$broadcast詳解

 更新時(shí)間:2019年03月07日 11:22:05   作者:littleLane  
這篇文章主要給大家介紹了關(guān)于Vue中情侶屬性$dispatch和$broadcast的相關(guān)資料,文中通過(guò)示例代碼以及圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

00 前言

$dispatch 和 $broadcast 作為一對(duì)情侶 💑屬性,在 Vue 1.0 中主要用來(lái)實(shí)現(xiàn)基于組件樹結(jié)構(gòu)的事件流通信 —— 通過(guò)向上或向下以冒泡的形式傳遞事件流,以實(shí)現(xiàn)嵌套父子組件的通信。但是由于其顯功能缺陷,在 Vue 2.0 中就被移除了。雖然 Vue 官網(wǎng)已經(jīng)不再支持使用 $dispatch 和 $broadcast 進(jìn)行組件通信,但是在很多基于 Vue 的 UI 框架中都有對(duì)其的封裝,包括 element-uiiview 等等。

那么 $dispatch 和 $broadcast 到底是怎么工作,其底層又是怎么實(shí)現(xiàn)的呢?接下來(lái),我們就詳細(xì)的說(shuō)一說(shuō)!

01 $dispatch 詳解

為了追根溯源,我們還是先去 Vue 1.0 的文檔你觀摩一下其概念吧!

概念:

Dispatch an event, first triggering it on the instance itself, and then propagates upward along the parent chain. The propagation stops when it triggers a parent event listener, unless that listener returns true. Any additional arguments will be passed into the listener's callback function.

上面的一段英文定義來(lái)自 Vue 1.0 官方文檔,其大致的意思是說(shuō):dispatch 是一個(gè)事件,首先會(huì)在自己實(shí)例本身上觸發(fā),然后沿父鏈向上傳播。當(dāng)它觸發(fā)父組件上的事件偵聽器時(shí)傳播即會(huì)停止,除非該偵聽器返回 true。 任何其他參數(shù)都將傳遞給偵聽器的回調(diào)函數(shù)。

參數(shù):

dispatch 會(huì)接收兩中參數(shù):event 是事件名稱,[...args] 是觸發(fā)事件時(shí)傳遞給回調(diào)函數(shù)的參數(shù)。

**例子:

// 創(chuàng)建一個(gè) parent 組件
var parent = new Vue();

// 創(chuàng)建一個(gè) child1 組件,其父組件指向 parent
var child1 = new Vue({ parent: parent });

// 創(chuàng)建一個(gè) child2 組件,其父組件指向 child1
var child2 = new Vue({ parent: child1 });

// 在 parent 組件監(jiān)聽名為 test 的事件,并綁定了一個(gè)回調(diào)函數(shù)
parent.$on('test', function () {
 console.log('parent notified');
});

// 在 child1 組件監(jiān)聽名為 test 的事件,并綁定了一個(gè)回調(diào)函數(shù)
child1.$on('test', function () {
 console.log('child1 notified');
});

// 在 child2 組件監(jiān)聽名為 test 的事件,并綁定了一個(gè)回調(diào)函數(shù)
child2.$on('test', function () {
 console.log('child2 notified');
});

說(shuō)到這里,parent、child1 和 child2 三個(gè)組件之間的關(guān)系可以展示成如下的關(guān)系圖:

// 在 child2 組件中通過(guò) dispatch 觸發(fā) test 事件
child2.$dispatch('test');

// 事件執(zhí)行會(huì)輸出如下結(jié)果
// -> "child2 notified"
// -> "child1 notified"

當(dāng)執(zhí)行 child2.$dispatch('test'); 時(shí),首先會(huì)觸發(fā) child2 組件里面監(jiān)聽的 test 事件的回調(diào)函數(shù),輸出 'child2 notified',根據(jù)上面官方文檔的定義,事件會(huì)沿著組件關(guān)系鏈一直向上傳遞,然后傳遞到 child1 組件,觸發(fā)監(jiān)聽事件輸出 "child1 notified",但是該偵聽器沒(méi)有返回 true,所以事件傳遞到此就結(jié)束了,最終的輸出結(jié)果就只有 "child2 notified" 和 "child1 notified"。

Vue 1.0 官方實(shí)現(xiàn)

在 Vue 1.0 版本中,$dispatch 實(shí)現(xiàn)的源碼放在 /src/instance/api/events.js 文件中,代碼很簡(jiǎn)單:

/**
 * Recursively propagate an event up the parent chain.
 * 遞歸地在父鏈上傳播事件。
 * @param {String} event
 * @param {...*} additional arguments
 */
// $dispatch 方法是定義在 Vue 的 prototype 上的
// 接受一個(gè)字符串類型的事件名稱
Vue.prototype.$dispatch = function (event) {
 // 首先執(zhí)行 $emit 觸發(fā)事件,將返回值保存在 shouldPropagate 中
 var shouldPropagate = this.$emit.apply(this, arguments)
 
 // 如果首次執(zhí)行的 $emit 方法返回的值不是 true 就直接返回
 // 如果返回值不是 true 就說(shuō)明組件邏輯不希望事件繼續(xù)往父組件進(jìn)行傳遞
 if (!shouldPropagate) return
 
 // 如果首次執(zhí)行 $emit 方法返回值是 true 就獲取當(dāng)前組件的 parent 組件實(shí)例
 var parent = this.$parent
 
 // 將函數(shù)接受的參數(shù)轉(zhuǎn)換成數(shù)組
 var args = toArray(arguments)
 
 // use object event to indicate non-source emit on parents
 // 根據(jù)傳入的事件名稱的參數(shù)組裝成 object
 args[0] = { name: event, source: this }
 
 // 循環(huán)知道組件的父組件
 while (parent) {
 // 在父組件中執(zhí)行 $emit 觸發(fā)事件
 shouldPropagate = parent.$emit.apply(parent, args)
 
 // 如果父組件 $emit 返回的是 true 就繼續(xù)遞歸祖父組件,否則就停止循環(huán)
 parent = shouldPropagate ? parent.$parent : null
 }
 
 // 最后返回當(dāng)前組件實(shí)例
 return this
}

element-ui 實(shí)現(xiàn)

在 element-ui 中,$dispatch 實(shí)現(xiàn)的源碼放在 /src/mixins/emitter.js 文件中,代碼很簡(jiǎn)單:

// 定義 dispatch 方法,接受三個(gè)參數(shù),分別是:組件名稱、將要觸發(fā)的事件名稱、回調(diào)函數(shù)傳遞的參數(shù)
dispatch(componentName, eventName, params) {
 // 獲取基于當(dāng)前組件的父組件實(shí)例,這里對(duì)父組件實(shí)例和根組件實(shí)例做了兼容處理
 var parent = this.$parent || this.$root;
 
 // 通過(guò)父組件的 $option 屬性獲取組件的名稱
 var name = parent.$options.componentName;

 // 當(dāng)相對(duì)當(dāng)前組件的父組件實(shí)例存在,而且當(dāng)父組件的名稱不存在或者父組件的名稱不等于傳入的組件名稱時(shí),執(zhí)行循環(huán)
 while (parent && (!name || name !== componentName)) {
 // 記錄父組件的父組件
 parent = parent.$parent;

 // 當(dāng)父組件的父組件存在時(shí),獲取祖父組件的名稱
 if (parent) {
  name = parent.$options.componentName;
 }
 }
 
 // 當(dāng)循環(huán)結(jié)束是,parent 的值就是最終匹配的組件實(shí)例
 if (parent) {
 // 當(dāng) parent 值存在時(shí)調(diào)用 $emit 方法
 // 傳入 parent 實(shí)例、事件名稱與 params 參數(shù)組成的數(shù)組
 // 觸發(fā)傳入事件名稱 eventName 同名的事件
 parent.$emit.apply(parent, [eventName].concat(params));
 }
}

差異分析

仔細(xì)看完實(shí)現(xiàn) $dispatch 方式的兩個(gè)版本的代碼,大家是不是發(fā)現(xiàn),兩個(gè)版本的實(shí)現(xiàn)和功能差異性還是很大的。

1、接受參數(shù):Vue 實(shí)現(xiàn)版本只會(huì)接受一個(gè)字符串類型的事件名稱為參數(shù),而 element-ui 實(shí)現(xiàn)的版本會(huì)接受三個(gè)參數(shù),分別是:需要觸發(fā)事件的組件名稱、將要觸發(fā)的事件名稱、回調(diào)函數(shù)傳遞的參數(shù);

2、實(shí)現(xiàn)功能:Vue 實(shí)現(xiàn)版本觸發(fā)事件一直會(huì)順著組件鏈向上進(jìn)行傳遞,知道父組件中的偵聽器沒(méi)有返回 true,在這個(gè)期間所有的組件都會(huì)執(zhí)行事件的響應(yīng),包括當(dāng)前組件本身,而 element-ui 實(shí)現(xiàn)版本會(huì)不斷的基于當(dāng)前組件向父組件進(jìn)行遍歷,直至找到和接受的組件名稱匹配,就會(huì)停止遍歷,觸發(fā)匹配組件中的監(jiān)聽事件。

10 $broadcast 詳解

上面詳細(xì)的說(shuō)完 $dispatch 方法的實(shí)現(xiàn)和 Vue 實(shí)現(xiàn)版本與 element-ui 實(shí)現(xiàn)版本的區(qū)別,下面就該說(shuō)說(shuō) $broadcast,畢竟他們是情侶屬性嘛。

概念

Broadcast an event that propagates downward to all descendants of the current instance. Since the descendants expand into multiple sub-trees, the event propagation will follow many different “paths”. The propagation for each path will stop when a listener callback is fired along that path, unless the callback returns true.

broadcast 是一個(gè)事件,它向下傳播到當(dāng)前實(shí)例的所有后代。由于后代擴(kuò)展為多個(gè)子樹,事件傳播將會(huì)遵循許多不同的“路徑”。 除非回調(diào)返回 true,否則在沿該路徑觸發(fā)偵聽器回調(diào)時(shí),每個(gè)路徑的傳播將會(huì)停止。

參數(shù)

broadcast 會(huì)接收兩中參數(shù):event 是事件名稱,[...args] 是觸發(fā)事件時(shí)傳遞給回調(diào)函數(shù)的參數(shù)。

例子

// 創(chuàng)建 parent 組件實(shí)例
var parent = new Vue()

// 創(chuàng)建 child1 組件實(shí)例,其父組件指向 parent
var child1 = new Vue({ parent: parent })

// 創(chuàng)建 child2 組件實(shí)例,其父組件指向 parent
var child2 = new Vue({ parent: parent })

// 創(chuàng)建 child3 組件實(shí)例,其父組件指向 child2
var child3 = new Vue({ parent: child2 })

// 在 child1 組件監(jiān)聽名為 test 的事件,并綁定了一個(gè)回調(diào)函數(shù)
child1.$on('test', function () {
 console.log('child1 notified')
})

// 在 child2 組件監(jiān)聽名為 test 的事件,并綁定了一個(gè)回調(diào)函數(shù)
child2.$on('test', function () {
 console.log('child2 notified')
})

// 在 child3 組件監(jiān)聽名為 test 的事件,并綁定了一個(gè)回調(diào)函數(shù)
child3.$on('test', function () {
 console.log('child3 notified')
})

parent、child1、child2 和 child3 四個(gè)組件之間的關(guān)系可以展示成如下的關(guān)系圖:


parent.$broadcast('test')
// -> "child1 notified"
// -> "child2 notified"

當(dāng)執(zhí)行 parent.$broadcast('test'); 時(shí),事件流會(huì)以 parent 組件為起點(diǎn)向 parent 的子組件進(jìn)行傳遞,根據(jù)事件綁定的順序,雖然 parent 組件有兩個(gè)同級(jí)的 child1 和 child2 ,但是事件流會(huì)先觸發(fā) child1 里面的綁定事件,此時(shí)會(huì)輸出 "child1 notified",然后事件流到達(dá) child2 組件,會(huì)觸發(fā) child2 組件中的綁定事件,輸出 "child2 notified"。到這時(shí),child2 組件中的偵聽器并沒(méi)有返回 true,所以事件傳遞到此就結(jié)束了,最終的輸出結(jié)果就只有 "child1 notified" 和 "child2 notified"。

Vue 1.0 官方實(shí)現(xiàn)

在 Vue 1.0 版本中,$broadcast 實(shí)現(xiàn)的源碼放在 /src/instance/api/events.js 文件中,代碼很簡(jiǎn)單:

/**
 * Recursively broadcast an event to all children instances.
 * 遞歸地向所有子實(shí)例廣播事件。
 * @param {String|Object} event
 * @param {...*} additional arguments
 */
// $dispatch 方法是定義在 Vue 的 prototype 上的
// 接受一個(gè)事件
Vue.prototype.$broadcast = function (event) {
 // 獲取傳入事件的類型,判斷是否為字符串
 var isSource = typeof event === 'string'
 
 // 校正 event 的值,當(dāng)接受 event 的類型為字符串時(shí)就直接使用,如果不是字符串就使用 event 上的 name 屬性 
 event = isSource ? event : event.name
 
 // if no child has registered for this event,
 // then there's no need to broadcast.
 // 如果當(dāng)前組件的子組件沒(méi)有注冊(cè)該事件,就直接返回,并不用 broadcast
 if (!this._eventsCount[event]) return
 
 // 獲取當(dāng)前組件的子組件
 var children = this.$children
 
 // 將函數(shù)接受的參數(shù)轉(zhuǎn)換成數(shù)組
 var args = toArray(arguments)
 
 // 如果傳入事件為字符串
 if (isSource) {
  // use object event to indicate non-source emit
  // on children
  // 根據(jù)傳入的事件名稱的參數(shù)組裝成 object
  args[0] = { name: event, source: this }
 }
 
 // 循環(huán)子組件
 for (var i = 0, l = children.length; i < l; i++) {
  var child = children[i]
  
  // 在每個(gè)子組件中調(diào)用 $emit 觸發(fā)事件
  var shouldPropagate = child.$emit.apply(child, args)
  
  // 判斷調(diào)用 $emit 返回的值是否為 true
  if (shouldPropagate) {
   // 如果調(diào)用 $emit 返回的值為 true,就遞歸孫子組件繼續(xù)廣播
   child.$broadcast.apply(child, args)
  }
 }
 
 // 最后返回當(dāng)前組件的實(shí)例
 return this
}

element-ui 實(shí)現(xiàn)

在 element-ui 中,$broadcast 實(shí)現(xiàn)的源碼放在 /src/mixins/emitter.js 文件中,代碼很簡(jiǎn)單:

// 定義 broadcast 方法,接受三個(gè)參數(shù),分別是:組件名稱、將要觸發(fā)的事件名稱、回調(diào)函數(shù)傳遞的參數(shù)
function broadcast(componentName, eventName, params) {
 // 依次循環(huán)當(dāng)前組件的子組件
 this.$children.forEach(child => {
  // 獲取每個(gè)子組件的名字
  var name = child.$options.componentName;

  // 判斷子組件的名字是否等于傳入的組件名稱
  if (name === componentName) {
   // 如果子組件的名字等于傳入的組件名稱就調(diào)用 $emit 觸發(fā)事件
   child.$emit.apply(child, [eventName].concat(params));
  } else {
   // 如果子組件的名字不等于傳入的組件名稱就遞歸遍歷調(diào)用 broadcast 孫子組件
   broadcast.apply(child, [componentName, eventName].concat([params]));
  }
 });
}

差異分析

和之前說(shuō)到的 $dispatch 一樣,這里的 $broadcast 的兩個(gè)實(shí)現(xiàn)版本也存在著巨大的差異:

1、接受參數(shù):Vue 實(shí)現(xiàn)版本只會(huì)接受一個(gè)字符串類型的事件名稱為參數(shù),而 element-ui 實(shí)現(xiàn)的版本會(huì)接受三個(gè)參數(shù),分別是:需要觸發(fā)事件的組件名稱、將要觸發(fā)的事件名稱、回調(diào)函數(shù)傳遞的參數(shù);

2、實(shí)現(xiàn)功能:Vue 實(shí)現(xiàn)的 $broadcast 觸發(fā)方式是默認(rèn)只觸發(fā)子代組件,不觸發(fā)孫子代組件,如果子代創(chuàng)建了監(jiān)聽且返回了true,才會(huì)向?qū)O子代組件傳遞事件。而 element-ui 實(shí)現(xiàn)的版本是直接向所有子孫后代組件傳遞,直至獲取到的子組件名稱等于傳入的組件名稱相等,才會(huì)觸發(fā)當(dāng)前子組件的監(jiān)聽事件,期間也沒(méi)有返回值的判定。

11 總結(jié)

說(shuō)到這里,$dispatch 和 $broadcast 的講解就結(jié)束了??赡艽蠹乙呀?jīng)知道了 Vue 2.0 版本為什么會(huì)將這兩個(gè)屬性移除。首先我們引入官網(wǎng)的說(shuō)法:

因?yàn)榛诮M件樹結(jié)構(gòu)的事件流方式實(shí)在是讓人難以理解,并且在組件結(jié)構(gòu)擴(kuò)展的過(guò)程中會(huì)變得越來(lái)越脆弱。這種事件方式確實(shí)不太好,我們也不希望在以后讓開發(fā)者們太痛苦。并且 $dispatch 和 $broadcast 也沒(méi)有解決兄弟組件間的通信問(wèn)題。

這樣來(lái)說(shuō) $dispatch 和 $broadcast 確實(shí)會(huì)有這樣的問(wèn)題。在前面的講解中,大家也不難發(fā)現(xiàn) $dispatch 主要是事件流由當(dāng)前組件往父組件流動(dòng),當(dāng)滿足一定條件的時(shí)候就會(huì)觸發(fā)當(dāng)前子組件的監(jiān)聽事件,$broadcast 的功能是事件流由當(dāng)前組件向子組件流動(dòng),當(dāng)滿足一定條件的時(shí)候就會(huì)觸發(fā)當(dāng)前子組件的監(jiān)聽事件。也就是說(shuō) $dispatch 和 $broadcast 主要解決了父子組件、嵌套父子組件的通信,并沒(méi)有解決兄弟組件的通信問(wèn)題,另一個(gè)方面這樣的事件流動(dòng)的方式是基于組件樹結(jié)構(gòu)的,當(dāng)業(yè)務(wù)越來(lái)越煩雜時(shí),這種方式會(huì)顯得極其繁瑣,甚至?xí)靵y到難以維護(hù),所以 Vue 2.0 版本移除這兩個(gè) API 是在意料之中的。

但是為什么三方 UI 庫(kù)都會(huì)封裝類似的這樣一個(gè)組件通信的方式呢?我的猜測(cè)可能是為了解決在父子層嵌套組件中,通過(guò) $dispatch 和 $broadcast 定向的向某個(gè)父或者子組件遠(yuǎn)程調(diào)用事件,這樣就避免了通過(guò)傳 props 或者使用 refs 調(diào)用組件實(shí)例方法的操作。這樣說(shuō)的話,$dispatch 和 $broadcast 也就其存在的價(jià)值,而并不是一無(wú)是處的,還是那句話:技術(shù)沒(méi)有好與壞,只有合適不合適!

好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • vue使用map代替Aarry數(shù)組循環(huán)遍歷的方法

    vue使用map代替Aarry數(shù)組循環(huán)遍歷的方法

    這篇文章主要介紹了vue使用map代替Aarry數(shù)組循環(huán)遍歷的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • vue?cli2?和?cli3去掉eslint檢查器報(bào)錯(cuò)的解決

    vue?cli2?和?cli3去掉eslint檢查器報(bào)錯(cuò)的解決

    這篇文章主要介紹了vue?cli2?和?cli3去掉eslint檢查器報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • Vue3中vuex的基本使用方法實(shí)例

    Vue3中vuex的基本使用方法實(shí)例

    Vuex是一個(gè)專為Vue.js應(yīng)用程序開發(fā)的狀態(tài)管理模式,它采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測(cè)的方式發(fā)生變化,下面這篇文章主要給大家介紹了關(guān)于Vue3中vuex的基本使用方法,需要的朋友可以參考下
    2022-04-04
  • vue3 與 vue2 優(yōu)點(diǎn)對(duì)比匯總

    vue3 與 vue2 優(yōu)點(diǎn)對(duì)比匯總

    隨著用vue3 的開發(fā)者越來(lái)越多,其必定是又她一定的有帶你,接下來(lái)這篇文章小編就為大家介紹vue3 對(duì)比 vue2 有什么優(yōu)點(diǎn)?感興趣的小伙伴請(qǐng)跟小編一起閱讀下文吧
    2021-09-09
  • vue+echarts圖表的基本使用步驟總結(jié)

    vue+echarts圖表的基本使用步驟總結(jié)

    這篇文章主要給大家介紹了關(guān)于vue+echarts圖表的基本使用步驟,Echarts是一款基于JavaScript的開源可視化圖表庫(kù),而Vue是一種流行的JavaScript框架,用于構(gòu)建用戶界,需要的朋友可以參考下
    2023-11-11
  • 在Vue中進(jìn)行數(shù)據(jù)分頁(yè)的實(shí)現(xiàn)方法

    在Vue中進(jìn)行數(shù)據(jù)分頁(yè)的實(shí)現(xiàn)方法

    在前端開發(fā)中,數(shù)據(jù)分頁(yè)是一個(gè)常見的需求,特別是當(dāng)處理大量數(shù)據(jù)時(shí),Vue作為一款流行的JavaScript框架,提供了強(qiáng)大的工具和生態(tài)系統(tǒng)來(lái)實(shí)現(xiàn)數(shù)據(jù)分頁(yè),本文將介紹如何在Vue中進(jìn)行數(shù)據(jù)分頁(yè),以及如何設(shè)計(jì)一個(gè)通用的分頁(yè)組件,需要的朋友可以參考下
    2023-10-10
  • vue cli 全面解析

    vue cli 全面解析

    vue是一套構(gòu)建用戶界面的漸進(jìn)式框架。這篇文章主要介紹了vue cli的相關(guān)知識(shí),本文給大家及時(shí)的非常全面,需要的朋友可以參考下
    2018-02-02
  • vue.js 使用axios實(shí)現(xiàn)下載功能的示例

    vue.js 使用axios實(shí)現(xiàn)下載功能的示例

    下面小編就為大家分享一篇vue.js 使用axios實(shí)現(xiàn)下載功能的示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看
    2018-03-03
  • antd?Vue實(shí)現(xiàn)Login登錄頁(yè)面布局案例詳解?附帶驗(yàn)證碼驗(yàn)證功能

    antd?Vue實(shí)現(xiàn)Login登錄頁(yè)面布局案例詳解?附帶驗(yàn)證碼驗(yàn)證功能

    這篇文章主要介紹了antd?Vue實(shí)現(xiàn)Login登錄頁(yè)面布局案例詳解附帶驗(yàn)證碼驗(yàn)證功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-05-05
  • vue跨域解決方法

    vue跨域解決方法

    這篇文章主要介紹了vue跨域解決方法 ,需要的朋友可以參考下
    2017-10-10

最新評(píng)論