本文作者系360奇舞團(tuán)前端開發(fā)工程師
EventBus 簡(jiǎn)介
事件總線(Event Bus)是一種用于組件間通信的模式,通常用于解決組件之間的解耦和簡(jiǎn)化通信的問題。在前端框架中,如 Vue.js,事件總線是一個(gè)常見的概念?;旧?,事件總線是一個(gè)能夠觸發(fā)和監(jiān)聽事件的機(jī)制,使得組件能夠在不直接依賴彼此的情況下進(jìn)行通信。事件總線可以是一個(gè)全局的單例對(duì)象,也可以是一個(gè)基于發(fā)布-訂閱模式的實(shí)現(xiàn)。
設(shè)計(jì)模式
在軟件架構(gòu)中,發(fā)布/訂閱(Publish–subscribe pattern)是一種消息范式,消息的發(fā)送者(稱為發(fā)布者)不會(huì)將消息直接發(fā)送給特定的接收者(稱為訂閱者),而是將發(fā)布的消息分為不同的類別,無需了解哪些訂閱者(如果存在)。同樣,訂閱者可以表達(dá)對(duì)一個(gè)或多個(gè)類別的興趣,只接收感興趣的消息,無需了解哪些發(fā)布者(如果存在)。
訂閱-發(fā)布模式(Publish-Subscribe Pattern)是一種軟件設(shè)計(jì)模式,也屬于行為型模式之一。它定義了一種對(duì)象間一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生變化時(shí),所有依賴于它的對(duì)象都會(huì)得到通知并自動(dòng)更新。這種模式降低了對(duì)象之間的直接耦合,使得系統(tǒng)更加靈活。該模式包含兩個(gè)主要角色:
發(fā)布者(Publisher): 負(fù)責(zé)發(fā)布(廣播)消息或事件的對(duì)象。當(dāng)發(fā)布者的狀態(tài)發(fā)生變化時(shí),它會(huì)通知所有已訂閱的對(duì)象。
訂閱者(Subscriber): 訂閱發(fā)布者的消息或事件的對(duì)象。訂閱者通過注冊(cè)自己的回調(diào)函數(shù)(或觀察者)來接收發(fā)布者的通知。
具體實(shí)現(xiàn)步驟如下:
發(fā)布者維護(hù)一個(gè)訂閱者列表(數(shù)組),用于存儲(chǔ)所有訂閱了它的對(duì)象。
訂閱者向發(fā)布者注冊(cè)自己的回調(diào)函數(shù)(或觀察者)。
當(dāng)發(fā)布者的狀態(tài)發(fā)生變化時(shí),它會(huì)遍歷訂閱者列表,調(diào)用每個(gè)訂閱者的回調(diào)函數(shù),通知它們狀態(tài)的變化。

EventBus 在前端(Vue 中)的使用
創(chuàng)建事件總線:
javascriptCopy?code
//?event-bus.js
import?Vue?from?'vue';
//?創(chuàng)建一個(gè)新的Vue實(shí)例作為事件總線
const?EventBus?=?new?Vue();
//?導(dǎo)出該實(shí)例,以便在應(yīng)用程序中的其他地方使用
export?default?EventBus;
組件 A:
<!--?ComponentA.vue?-->
??<template>
????<div>
??????<button?@click="emitEvent">觸發(fā)事件</button>
??</div>
??</template>
??<script>
??import?EventBus?from?'./event-bus.js';
export?default?{
??methods:?{
????emitEvent()?{
??????//?使用事件總線觸發(fā)名為?'custom-event'?的事件,并傳遞數(shù)據(jù)
??????EventBus.$emit('custom-event',?'這是傳遞的數(shù)據(jù)');
????}
??}
}
??</script>
組件 B:
<!--?ComponentB.vue?-->
??<template>
????<div>
??????<p>{{?eventData?}}</p>
????</div>
??</template>
??<script>
??import?EventBus?from?'./event-bus.js';
export?default?{
??data()?{
????return?{
??????eventData:?''
????};
??},
??mounted()?{
????//?在組件創(chuàng)建時(shí),通過事件總線監(jiān)聽?'custom-event'?事件
????EventBus.$on('custom-event',?eventData?=>?{
??????//?更新組件的數(shù)據(jù)
??????this.eventData?=?eventData;
??????console.log('收到事件,數(shù)據(jù)為:',?eventData);
????});
??}
}
??</script>
ComponentA組件通過點(diǎn)擊按鈕觸發(fā)了一個(gè)名為 custom-event 的事件,并傳遞了一些數(shù)據(jù)。ComponentB組件在創(chuàng)建時(shí)通過事件總線監(jiān)聽了這個(gè)事件,并在事件發(fā)生時(shí)更新了組件的數(shù)據(jù)。注意:使用事件總線時(shí)需要注意組件的生命周期,確保在不再需要監(jiān)聽事件的組件被銷毀時(shí)取消事件監(jiān)聽,以避免潛在的內(nèi)存泄漏。
銷毀
beforeDestroy()?{
????//?在組件銷毀前取消事件監(jiān)聽
????EventBus.$off('custom-event',?this.eventBusListener);
??}
EventBus 在前端(React 中)的使用
在 React 中,沒有像 Vue 中的事件總線那樣的直接內(nèi)置機(jī)制。React 通常使用 props 和回調(diào)函數(shù)來實(shí)現(xiàn)組件之間的通信。然而,如果你的應(yīng)用需要在不適用 props 傳遞的情況下進(jìn)行全局事件的訂閱和發(fā)布,可以使用第三方庫,比如 eventemitter3 或者 Redux。以下是使用 Event Emitter 的一個(gè)簡(jiǎn)單示例:
安裝 eventemitter3
npm?install?eventemitter3
創(chuàng)建全局的事件管理器
//?eventBus.js
import?{?EventEmitter?}?from?'eventemitter3';
const?eventBus?=?new?EventEmitter();
export?default?eventBus;
引入這個(gè)事件總線訂閱和發(fā)布事件:
//?ComponentA.jsx
import?React?from?'react';
import?eventBus?from?'./eventBus';
class?ComponentA?extends?React.Component?{
??emitEvent?=?()?=>?{
????eventBus.emit('custom-event',?'這是傳遞的數(shù)據(jù)');
??};
??render()?{
????return?(
??????<div>
????????<button?onClick={this.emitEvent}>觸發(fā)事件</button>
??????</div>
????);
??}
}
export?default?ComponentA;
//?ComponentB.jsx
import?React,?{?useState,?useEffect?}?from?'react';
import?eventBus?from?'./eventBus';
const?ComponentB?=?()?=>?{
??const?[eventData,?setEventData]?=?useState('');
??useEffect(()?=>?{
????const?eventBusListener?=?(data)?=>?{
??????setEventData(data);
??????console.log('收到事件,數(shù)據(jù)為:',?data);
????};
????eventBus.on('custom-event',?eventBusListener);
????return?()?=>?{
??????//?在組件卸載時(shí)取消事件監(jiān)聽
??????eventBus.off('custom-event',?eventBusListener);
????};
??},?[]);
??return?(
????<div>
??????<p>{eventData}</p>
????</div>
??);
};
export?default?ComponentB;
注意:在組件卸載**eventBus.off('custom-event', eventBusListener);**時(shí)取消事件監(jiān)聽以避免潛在的內(nèi)存泄漏。
使用 EventBus 優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
解耦組件: 事件總線能夠?qū)崿F(xiàn)組件之間的解耦,使得它們不需要直接引用或依賴彼此,提高了代碼的靈活性和可維護(hù)性。
簡(jiǎn)化通信: 對(duì)于一些簡(jiǎn)單的通信需求,事件總線提供了一種相對(duì)簡(jiǎn)單的方式,避免了通過 props 和回調(diào)函數(shù)傳遞數(shù)據(jù)時(shí)的繁瑣操作。
全局通信: 事件總線通常是全局性的,能夠在整個(gè)應(yīng)用程序中的任何地方進(jìn)行通信,適用于全局狀態(tài)的傳遞和應(yīng)用的整體控制。
跨組件通信: 事件總線可以方便地實(shí)現(xiàn)非父子組件之間的通信,而不需要在組件之間建立直接的關(guān)聯(lián)。
缺點(diǎn):
全局狀態(tài)管理: 使用事件總線可能引入全局狀態(tài),導(dǎo)致應(yīng)用狀態(tài)變得難以追蹤和理解,特別是在大型應(yīng)用中。
難以調(diào)試: 全局性的事件監(jiān)聽和觸發(fā)可能使得追蹤代碼執(zhí)行流程和調(diào)試變得更加困難,尤其是在復(fù)雜的應(yīng)用場(chǎng)景下。
潛在的性能問題: 大量的全局事件監(jiān)聽和觸發(fā)可能導(dǎo)致性能問題,尤其是在頻繁觸發(fā)事件的情況下。
不明確的數(shù)據(jù)流向: 使用事件總線時(shí),數(shù)據(jù)的流向相對(duì)不明確,可能增加代碼的復(fù)雜性,使得應(yīng)用程序的數(shù)據(jù)流變得更加難以理解。
安全性問題: 由于事件總線是全局的,可能存在安全風(fēng)險(xiǎn),例如某個(gè)組件監(jiān)聽了不應(yīng)該被其它組件觸發(fā)的敏感事件。
總結(jié)
綜合考慮,對(duì)于小型應(yīng)用或簡(jiǎn)單的場(chǎng)景,事件總線是一個(gè)方便的工具。但在大型應(yīng)用或需要更嚴(yán)格狀態(tài)管理和調(diào)試的情況下,可能需要考慮使用更復(fù)雜的狀態(tài)管理工具,如 Vuex 或 Redux。使用事件總線時(shí),需要謹(jǐn)慎使用,避免濫用全局狀態(tài)和事件。
-?END?-
關(guān)于奇舞團(tuán)
奇舞團(tuán)是 360 集團(tuán)最大的大前端團(tuán)隊(duì),代表集團(tuán)參與 W3C 和 ECMA 會(huì)員(TC39)工作。奇舞團(tuán)非常重視人才培養(yǎng),有工程師、講師、翻譯官、業(yè)務(wù)接口人、團(tuán)隊(duì) Leader 等多種發(fā)展方向供員工選擇,并輔以提供相應(yīng)的技術(shù)力、專業(yè)力、通用力、領(lǐng)導(dǎo)力等培訓(xùn)課程。奇舞團(tuán)以開放和求賢的心態(tài)歡迎各種優(yōu)秀人才關(guān)注和加入奇舞團(tuán)。
文章來源:http://www.zghlxwxcb.cn/news/detail-787269.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-787269.html
到了這里,關(guān)于探索前端跨組件通信:EventBus在Vue和React中的應(yīng)用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!