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;分…

【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对象的默…

21.Word:小赵-毕业论文排版❗【39】

目录 题目​ NO1.2 NO3.4 NO5.6 NO7.8.9 NO10.11.12 题目 NO1.2 自己的论文当中接收老师的修改&#xff1a;审阅→比较→源文档&#xff1a;考生文件夹&#xff1a;Word.docx→修订的文档&#xff1a;考生文件夹&#xff1a;教师修改→确定→接收→接收所有修订将合并之…

深度学习 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需要一个程序来计算一个数字有多少种不同的…

RabbitMQ5-死信队列

目录 死信的概念 死信的来源 死信实战 死信之TTl 死信之最大长度 死信之消息被拒 死信的概念 死信&#xff0c;顾名思义就是无法被消费的消息&#xff0c;一般来说&#xff0c;producer 将消息投递到 broker 或直接到queue 里了&#xff0c;consumer 从 queue 取出消息进…

10JavaWeb——SpringBootWeb案例01

前面我们已经讲解了Web前端开发的基础知识&#xff0c;也讲解了Web后端开发的基础(HTTP协议、请求响应)&#xff0c;并且也讲解了数据库MySQL&#xff0c;以及通过Mybatis框架如何来完成数据库的基本操作。 那接下来&#xff0c;我们就通过一个案例&#xff0c;来将前端开发、后…

JAVA 接口、抽象类的关系和用处 详细解析

接口 - Java教程 - 廖雪峰的官方网站 一个 抽象类 如果实现了一个接口&#xff0c;可以只选择实现接口中的 部分方法&#xff08;所有的方法都要有&#xff0c;可以一部分已经写具体&#xff0c;另一部分继续保留抽象&#xff09;&#xff0c;原因在于&#xff1a; 抽象类本身…

ResNeSt: Split-Attention Networks论文学习笔记

这张图展示了一个名为“Split-Attention”的神经网络结构&#xff0c;该结构在一个基数组&#xff08;cardinal group&#xff09;内进行操作。基数组通常指的是在神经网络中处理的一组特征或通道。图中展示了如何通过一系列操作来实现对输入特征的注意力机制。 以下是图中各部…

设计模式Python版 原型模式

文章目录 前言一、原型模式二、原型模式示例三、原型管理器 前言 GOF设计模式分三大类&#xff1a; 创建型模式&#xff1a;关注对象的创建过程&#xff0c;包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。结构型模式&#xff1a;关注类和对…

神经网络的通俗介绍

人工神经网络&#xff0c;是一种模仿人类大脑工作原理的数学模型。人类的大脑是由无数的小“工作站”组成的&#xff0c;每个工作站叫做“神经元”。这些神经元通过“电线”互相连接&#xff0c;负责接收、处理和传递信息。 一、人类大脑神经网络 人类大脑的神经网络大概长这…

OpenEuler学习笔记(八):安装OpenEuler

在VMware Workstation中安装OpenEuler 准备工作 下载并安装VMware Workstation虚拟机软件。前往OpenEuler官网下载OpenEuler系统镜像文件。 创建虚拟机 打开VMware Workstation&#xff0c;点击“创建新的虚拟机”&#xff0c;选择“自定义”&#xff0c;点击“下一步”。选择…

Leetcode::119. 杨辉三角 II

119. 杨辉三角 II 已解答 简单 相关标签 相关企业 给定一个非负索引 rowIndex&#xff0c;返回「杨辉三角」的第 rowIndex 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: rowIndex 3 输出: [1,3,3,1]示例 2: 输入: rowIndex 0…

让Android adb支持互联网调试脱离局域网

某些特殊场景下由于不方便&#xff0c;手机不在身边&#xff0c;但需要进行adb调试。 首先可以先开启adb的无线调试模式&#xff0c;我使用的是第二种方式。 在Android手机上安装一个终端模拟器&#xff0c;并赋予root权限&#xff0c;随后执行&#xff1a; setprop service.…

Dest1ny漏洞库:用友 U8-CRM 系统 ajaxgetborrowdata.php 存在 SQL 注入漏洞

用友U8-CRM系统ajaxgetborrowdata.php存在SQL注入漏洞&#xff0c;文件多个方法存在SQL注入漏洞&#xff0c;未经身份验证的攻击者通过漏洞执行任意SQL语句&#xff0c;调用xp_cmdshell写入后门文件&#xff0c;执行任意代码&#xff0c;从而获取到服务器权限。 hunter app.n…

能说说MyBatis的工作原理吗?

大家好&#xff0c;我是锋哥。今天分享关于【Redis为什么这么快?】面试题。希望对大家有帮助&#xff1b; 能说说MyBatis的工作原理吗&#xff1f; MyBatis 是一款流行的持久层框架&#xff0c;它通过简化数据库操作&#xff0c;帮助开发者更高效地与数据库进行交互。MyBatis…

DeepSeek崛起:中国AI新星如何撼动全球资本市场格局

引言 近期&#xff0c;中国人工智能实验室DeepSeek发布的两款开源模型——DeepSeek V3和DeepSeek R1——以其优异的性能和低廉的成本迅速爆火&#xff0c;引发了全球资本市场的震动&#xff0c;尤其对美国资本市场产生了显著影响。DeepSeek R1更是能够在数学、代码和推理任务上…

将5分钟安装Thingsboard 脚本升级到 3.9

稍微花了一点时间&#xff0c;将5分钟安装Thingsboard 脚本升级到最新版本 3.9。 [rootlab5 work]# cat one-thingsboard.shell echo "test on RHEL 8.10 " source /work/java/install-java.shell source /work/thingsboard/thingsboard-rpm.shell source /work/po…