vue事件總線(原理、優缺點)

目錄

  • 一、原理
  • 二、使用方法
  • 三、優缺點
    • 優點
    • 缺點
  • 四、使用注意事項
  • 具體代碼
  • 參考:

一、原理

在Vue中,事件總線(Event Bus)是一種可實現任意組件間通信的通信方式。
要實現這個功能必須滿足兩點要求:
(1)所有組件都能看到它;
(2)可以進行事件的監聽;

對于第一個要求,Vue通過內置關系VueComponent.prototype.__proto__ === Vue.prototype,使組件實例對象可以訪問到Vue原型上的屬性和方法,所以只需把事件總線放在Vue的原型對象上,它就可以被所有組件訪問。

至于第二個要求,Vue在原型對象上定義了$on、$emit、$off等方法,用于實現事件監聽。基本原理是基于消息訂閱發布:調用$on方法時,將函數存在以事件名為key的數組里;當調用$emit時,獲取相應數組里的所有函數,并逐個執行。

源碼位置:https://github.com/vuejs/vue/blob/main/src/core/instance/events.ts
在這里插入圖片描述
在這里插入圖片描述
所以事件總線就是一個定義在Vue原型對象上的Vue實例。

new Vue({el: '#app',render: h => h(App),beforeCreate() {Vue.prototype.$bus = this;}
})

二、使用方法

一個A組件想給B組件發送數據的場景:
A組件:

// A組件想發送數據,則觸發事件并傳遞參數,參數可以是零個到多個
this.$bus.$emit(事件名, 參數);

B組件:

// B組件想接收數據,則在B組件中給$bus綁定自定義事件,事件的回調留在B組件自身
this.$bus.$on(事件名, 回調函數);
// 需要在beforeDestory鉤子中解綁事件,避免內存泄露
this.$bus.$off(事件名, 回調函數);

三、優缺點

優點

  1. 任意組件間通信
  2. 組件解耦
    通過使用事件總線,可以將組件之間的直接依賴關系解耦,使組件更加獨立和可復用。組件只需要關注自身的功能,而不用關心其他組件的實現細節。

缺點

  1. 只能被動接收數據,不能隨時獲取狀態
    如果需要隨時獲取狀態,可以使用狀態管理工具Vuex或者Pinia。
  2. 代碼難以調試、數據流向難以追蹤
    在大型應用中,事件總線的濫用可能導致組件之間的關系變得混亂,導致追蹤代碼執行流程和調試變得更加困難。
  3. 潛在的性能問題
    大量的全局事件監聽和觸發可能導致性能問題,尤其是在頻繁觸發事件的情況下。

四、使用注意事項

  1. 避免事件命名沖突
    由于事件總線是一個全局的對象,為避免事件命名沖突導致錯誤觸發/解綁事件,建議使用具唯一性的命名空間前綴區分不同的事件。
  2. 避免錯誤解綁事件
    在解綁事件時,一定要帶上事件名和相應的回調函數,否則可能會錯誤解綁其他組件的事件,影響其他組件的正常運行。
// 僅將回調函數與事件名解綁
this.$bus.$off(事件名, 回調函數);
// 解綁事件名下的所有事件
this.$bus.$off(事件名);
// 解綁所有事件
this.$bus.$off();
  1. 回調函數不能是匿名函數
    匿名函數會導致事件無法正常被解綁
    在這里插入圖片描述
  2. 沒有解綁事件,可能導致內存泄露
    當組件被銷毀時,相關DOM結點已經從DOM樹分離出來了,但是還有綁定的事件指向它,導致這些DOM結點無法被垃圾回收,一直在內存里面,就會引發內存泄露。
    所以在組件銷毀時,可以在組件的beforeDestroy鉤子中使用$off方法解綁事件,以防止內存泄漏。
    沒有解綁時:
    在這里插入圖片描述

正常解綁時:
在這里插入圖片描述

  1. 注意事件的傳參
    在發送事件時,可以通過參數傳遞數據。但請確保傳遞的數據是簡單且不可變的,避免直接傳遞引用類型的數據,以免造成數據不一致或意外的修改。
    receive(receiveData) {this.receiveData = receiveData;// 在接收的組件中修改了對象中的值,發送的組件中的值也會改變this.receiveData.text = '111';},
  1. 慎用全局事件
    全局事件有很大的便利性,但也容易造成不可預測的問題。在使用事件線時,盡量避免濫用全局事件,可以考慮使用更明確的通信方式。
    (1)props和自定義事件應該是父子間通信的首選;
    (2)兄弟節點通信可通過它們的父節點進行;
    (3)隔代組件通信可以使用provide/inject。它可以避免“prop逐級透傳”問題,即prop需要通過許多層級的組件傳遞下去,但這些組件本身可能并不需要那些prop。
    (4)全局共享的數據管理,一般使用Pinia或Vuex等工具。

具體代碼

main.js

import Vue from 'vue'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css'
import App from './App.vue'Vue.config.productionTip = false
Vue.use(ElementUI)new Vue({el: '#app',render: h => h(App),beforeCreate() {Vue.prototype.iBus = this;}
})

App.vue(用v-if就可以觸發組件銷毀,不一定要用tab)

<template><div><el-tabs v-model="editableTabsValue" type="card" closable @tab-remove="closeTab"><el-tab-panev-for="item in editableTabs":key="item.name":label="item.title":name="item.name"><send-tab v-if="item.name === 'sendTab'"/><receive-tab v-else/></el-tab-pane></el-tabs></div>
</template><script>import ReceiveTab from "@/components/ReceiveTab.vue";
import SendTab from "@/components/SendTab.vue";export default {name: 'App',components: {SendTab, ReceiveTab},data() {return {editableTabsValue: 'sendTab',editableTabs: [{title: '發送頁面',name: 'sendTab',},{title: '接收頁面',name: 'receiveTab',},],tabIndex: 1,}},methods: {closeTab(targetName) {let tabs = this.editableTabs;let activeName = this.editableTabsValue;if (activeName === targetName) {tabs.forEach((tab, index) => {if (tab.name === targetName) {let nextTab = tabs[index + 1] || tabs[index - 1];if (nextTab) {activeName = nextTab.name;}}});}this.editableTabsValue = activeName;this.editableTabs = tabs.filter(tab => tab.name !== targetName);}}
}
</script>

SendTab.vue

<script>
export default {name: "SendTab",data() {return {input: {text: '',},}},methods: {send() {console.log('--------------emit', this.iBus._events)this.iBus.$emit('bus-demo', this.input, 'data2');},},beforeDestroy() {console.log('--------------發送組件的beforeDestroy')},
}
</script><template><div><el-input style="width: 250px" v-model="input.text"/><el-button type="primary" @click="send">發送數據</el-button></div>
</template>

ReceiveTab.vue

<script>
export default {name: "ReceiveTab",data() {return {receiveData: null,}},created() {this.iBus.$on('bus-demo', this.receive);// this.iBus.$on('anon-func', () => {//   console.log('---------------匿名函數')// });console.log('--------------on', this.iBus._events)},beforeDestroy() {this.iBus.$off('bus-demo', this.receive);// this.iBus.$off('anon-func', () => {//   console.log('---------------匿名函數')// });console.log('--------------接收組件的beforeDestroy')},methods: {receive(receiveData, otherData) {this.receiveData = receiveData;// this.receiveData.text = '111';console.log('---------第二個參數', otherData)},},
}
</script><template><span>接收到的數據:{{ receiveData }}</span>
</template>

參考:

  • Vue3遷移指南-事件總線
  • 尚硅谷Vue教程-84/85事件總線
  • 【Vue知識】$on和$emit的實現原理
  • 詳解Vue事件總線的原理與應用:EventBus
  • 一個Vue頁面的內存泄露分析

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/67324.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/67324.shtml
英文地址,請注明出處:http://en.pswp.cn/web/67324.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

圖像處理之HSV顏色空間

目錄 1 RGB 的局限性 2 HSV 顏色空間 3 RGB與HSV相互轉換 4 HSV顏色模型對圖像的色相、飽和度和明度進行調節 5 演示Demo 5.1 開發環境 5.2 功能介紹 5.3 下載地址 參考 1 RGB 的局限性 RGB 是我們接觸最多的顏色空間&#xff0c;由三個通道表示一幅圖像&#xff0c;分…

DeepSeek是由杭州深度求索人工智能基礎技術研究有限公司(簡稱“深度求索”)發布的一系列人工智能模型

DeepSeek是由杭州深度求索人工智能基礎技術研究有限公司&#xff08;簡稱“深度求索”&#xff09;發布的一系列人工智能模型&#xff0c;其在知識類任務上展現出了卓越的性能。以下是對DeepSeek的詳細介紹&#xff0c;內容雖無法達到10000字&#xff0c;但會盡可能全面且深入地…

【C++高并發服務器WebServer】-9:多線程開發

本文目錄 一、線程概述1.1 線程和進程的區別1.2 線程之間共享和非共享資源1.3 NPTL 二、線程操作2.1 pthread_create2.2 pthread_exit2.3 pthread_join2.4 pthread_detach2.5 patch_cancel2.6 pthread_attr 三、實戰demo四、線程同步五、死鎖六、讀寫鎖七、生產消費者模型 一、…

14-6-1C++STL的list

(一&#xff09;list容器的基本概念 list容器簡介&#xff1a; 1.list是一個雙向鏈表容器&#xff0c;可高效地進行插入刪除元素 2.list不可以隨機存取元素&#xff0c;所以不支持at.(pos)函數與[ ]操作符 &#xff08;二&#xff09;list容器頭部和尾部的操作 list對象的默…

在sortablejs的拖拽排序情況下阻止input拖拽事件

如題 問題 在vue3的elementPlus的table中&#xff0c;通過sortablejs添加了行拖拽功能&#xff0c;但是在行內會有輸入框&#xff0c;此時拖拽輸入框會觸發sortablejs的拖拽功能 解決 基于這個現象&#xff0c;我懷疑是由于拖拽事件未綁定而冒泡到后面的行上從而導致的拖拽…

21.Word:小趙-畢業論文排版?【39】

目錄 題目? NO1.2 NO3.4 NO5.6 NO7.8.9 NO10.11.12 題目 NO1.2 自己的論文當中接收老師的修改&#xff1a;審閱→比較→源文檔&#xff1a;考生文件夾&#xff1a;Word.docx→修訂的文檔&#xff1a;考生文件夾&#xff1a;教師修改→確定→接收→接收所有修訂將合并之…

leetcode_鏈表 876.鏈表的中間節點

876.鏈表的中間節點 給你單鏈表的頭結點 head &#xff0c;請你找出并返回鏈表的中間結點。如果有兩個中間結點&#xff0c;則返回第二個中間結點。思路&#xff1a;快慢指針&#xff0c;創建兩個指針fast和slow&#xff0c;fast指針每次移動兩步&#xff0c;slow指針每次移動…

深度學習 DAY3:NLP發展史及早期的前饋神經網絡(ANN)及多任務學習

NLP發展史 NLP發展脈絡簡要梳理如下&#xff1a; 2001 - Neural language models&#xff08;神經語言模型&#xff09; 2008 - Multi-task learning&#xff08;多任務學習&#xff09; 2013 - Word embeddings&#xff08;詞嵌入&#xff09; 2013 - Neural networks for NL…

全面了解 Web3 AIGC 和 AI Agent 的創新先鋒 MelodAI

不管是在傳統領域還是 Crypto&#xff0c;AI 都是公認的最有前景的賽道。隨著數字內容需求的爆炸式增長和技術的快速迭代&#xff0c;Web3 AIGC&#xff08;AI生成內容&#xff09;和 AI Agent&#xff08;人工智能代理&#xff09;正成為兩大關鍵賽道。 AIGC 通過 AI 技術生成…

54.數字翻譯成字符串的可能性|Marscode AI刷題

1.題目 問題描述 小M獲得了一個任務&#xff0c;需要將數字翻譯成字符串。翻譯規則是&#xff1a;0對應"a"&#xff0c;1對應"b"&#xff0c;依此類推直到25對應"z"。一個數字可能有多種翻譯方法。小M需要一個程序來計算一個數字有多少種不同的…

FileReader使用

FileReader : 讀取文件內容的api&#xff0c;&#xff0c;&#xff0c;在前端處理上傳的文件&#xff0c;&#xff0c;比如預覽圖片 readAsDataURL(file) &#xff1a; 讀取為base64編碼的 data urlreadAsText() &#xff1a; 讀取為文本readAsArrayBuffer() : 讀取為二進制 …

RabbitMQ5-死信隊列

目錄 死信的概念 死信的來源 死信實戰 死信之TTl 死信之最大長度 死信之消息被拒 死信的概念 死信&#xff0c;顧名思義就是無法被消費的消息&#xff0c;一般來說&#xff0c;producer 將消息投遞到 broker 或直接到queue 里了&#xff0c;consumer 從 queue 取出消息進…

JavaScript系列(48)-- 3D渲染引擎實現詳解

JavaScript 3D渲染引擎實現詳解 &#x1f3ae; 今天&#xff0c;讓我們深入探討JavaScript的3D渲染引擎實現。通過WebGL和現代JavaScript技術&#xff0c;我們可以構建一個功能完整的3D渲染系統。 3D渲染基礎概念 &#x1f31f; &#x1f4a1; 小知識&#xff1a;3D渲染引擎的…

10JavaWeb——SpringBootWeb案例01

前面我們已經講解了Web前端開發的基礎知識&#xff0c;也講解了Web后端開發的基礎(HTTP協議、請求響應)&#xff0c;并且也講解了數據庫MySQL&#xff0c;以及通過Mybatis框架如何來完成數據庫的基本操作。 那接下來&#xff0c;我們就通過一個案例&#xff0c;來將前端開發、后…

【面試題】 Java 三年工作經驗(2025)

問題列表 為什么選擇 spring boot 框架&#xff0c;它與 Spring 有什么區別&#xff1f;spring mvc 的執行流程是什么&#xff1f;如何實現 spring 的 IOC 過程&#xff0c;會用到什么技術&#xff1f;spring boot 的自動化配置的原理是什么&#xff1f;如何理解 spring boot 中…

JAVA 接口、抽象類的關系和用處 詳細解析

接口 - Java教程 - 廖雪峰的官方網站 一個 抽象類 如果實現了一個接口&#xff0c;可以只選擇實現接口中的 部分方法&#xff08;所有的方法都要有&#xff0c;可以一部分已經寫具體&#xff0c;另一部分繼續保留抽象&#xff09;&#xff0c;原因在于&#xff1a; 抽象類本身…

ResNeSt: Split-Attention Networks論文學習筆記

這張圖展示了一個名為“Split-Attention”的神經網絡結構&#xff0c;該結構在一個基數組&#xff08;cardinal group&#xff09;內進行操作。基數組通常指的是在神經網絡中處理的一組特征或通道。圖中展示了如何通過一系列操作來實現對輸入特征的注意力機制。 以下是圖中各部…

數據收集后臺服務概要設計

為了幫助大家設計一個數據指標匯總的后端應用&#xff0c;我將提供一個概要設計和表設計的建議。這個設計將基于常見的數據收集需求&#xff0c;假設你需要收集、存儲和匯總來自不同數據源的指標數據。 1. 概要設計 1.1 系統架構 數據收集層&#xff1a;負責從不同數據源&am…

探秘 TCP TLP:從背景到實現

回家的路上還討論了個關于 TCP TLP 的問題&#xff0c;閑著無事縷一縷。本文內容參考自 Tail Loss Probe (TLP): An Algorithm for Fast Recovery of Tail Losses 以及 Linux 內核源碼。 TLP&#xff0c;先說緣由。自 TCP 引入 Fast retrans 機制就是為了盡力避免 RTO&#xf…

設計模式Python版 原型模式

文章目錄 前言一、原型模式二、原型模式示例三、原型管理器 前言 GOF設計模式分三大類&#xff1a; 創建型模式&#xff1a;關注對象的創建過程&#xff0c;包括單例模式、簡單工廠模式、工廠方法模式、抽象工廠模式、原型模式和建造者模式。結構型模式&#xff1a;關注類和對…