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.mzph.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;关注类和对…