当前位置: 首页 > news >正文

vue3跨组件(多组件)通信:事件总线【Event Bus】

★推荐方案:使用 `events` npm库;
可用范围:vue、react、angular等任何框架都可使用;且使用方式完全一致;

本文仅介绍、讲解对web页面端项目的常用API;通过events实现事件总线功能;

event库概述:本次所使用到的库为通用库,若在node环境使用则无需npm安装,本身自带的;浏览器环境下使用才需要npm安装。
events库是从 Node.js 上移植Events模块的功能,因此可用的API完全一致(除了仅限在node环境下使用的API);
若想进一步深入,去看node官网的event文档即可。(注意版本差异!根据npm文档的描述,该库目前并未同步最新Node里对应的events模块)

在VUE3的官方文档中描述到:【平级组件或是跨越多层嵌套的组件间通信,应使用一个外部的事件总线,或是使用一个全局状态管理方案】。全局状态管理就则是像pinia这种,本文就主要讲述事件总线;
VUE2的话直接用官方API提供的即可,当然如果vue2的相关API实现的事件总线不满足需求,那自然也是推荐使用events库的!


events库使用方式:

1、安装

npm install events

2、引入使用、封装

import { EventEmitter } from 'events';// 大家根据各自业务需求自行封装对应风格的事件总线模块;
export const emitter = new EventEmitter();// 创建多个事件总线,互不干扰。
export const emitter2 = new EventEmitter();

这样我们就创建好了一个简单的事件总线实例,也可以创建多个事件总线

3、注册监听器:eventEmitter.on() 与监听函数的this指向;

类型:on(eventName: string | symbol, listener: (...args: any[]) => void): this;

别名:emitter.addListener(eventName, listener)


import { emitter,emitter2 } from '@/utils/events'// 可接收多个参数,若emit触发该监听函数时未传参则是undefined// 第一个参数类型:eventName: string | symbol// 第二个参数类型: listener: (...args: any[]) => voidemitter.on('test1',function (val,val2,val3){console.log(val,val2,val3,'可接受多个参数!');console.log(this,'该this指向为emitter实例,若监听函数为箭头函数,则该处this指向不用我解释了吧?这是基础啊');})emitter.on('test1',function (){console.log('可多次注册同名的test1监听函数;注意事项看 《7、监听数量相关内容》 ');})// 按上一步所示,不同事件总线实例创建监听器时eventName同名也不会互相影响;emitter2.on('test1',(val)=>{console.log(val);})function emitTest() { // 标准写法,这样才可off卸载监听函数;上面2个例子只是展示功能作用;console.log('葬送的芙莉莲');}emitter.on('emitTest',emitTest)emitter.off('emitTest',emitTest)

另外,EventEmitter 按照注册的顺序同步地调用所有监听器。 这确保了事件的正确排序,并有助于避免竞争条件和逻辑错误。 

4、触发监听器事件:eventEmitter.emit()

emit类型为:emit(eventName: string | symbol, ...args: any[]): boolean;

下面代码中的 `emitter.emit('test1',1,'向监听的函数传入多个参数') ` 表示触发所有 test1 的监听函数,并传入后面那2个参数。

返回值:如果事件有监听器,则返回 true,否则返回 false

import { emitter,emitter2 } from '@/utils/events'emitter.emit('test1',1,'向监听的函数传入多个参数')emitter2.emit('test1','来自 emitter2 的问候.')// boolean返回值表示未触发该监听函数;下面两个emit返回的结果都是falseconst has = emitter2.emit('emitTest','返回false') // 就算on创建过监听函数,off后此时触发不到也是返回falseconst has2 = emitter2.emit('test666','返回false')

5、仅触发一次监听器事件:eventEmitter.once() 

类型:once(eventName: string | symbol, listener: (...args: any[]) => void): this;

使用 eventEmitter.once() 方法,可以注册一个监听器,该监听器最多为特定事件调用一次。 一旦事件被触发,则监听器就会 先被注销 然后再调用该监听函数。

import { emitter,emitter2 } from '@/utils/events'let countt = 0emitter.once('test2',function () {++counttconsole.log(countt);})

import { emitter } from '@/utils/events'function demo (){let has = emitter.emit('test2')console.log(has); 
}
demo(); // 第一次Log是true,emit.once执行一次后就会销毁
demo(); // 销毁后再执行自然是找不到该监听函数的,所以返回false

6、卸载/销毁 监听器    emitter.off()

类型:off(eventName: string | symbol, listener: (...args: any[]) => void): this;

别名:emitter.removeListener()

从名为 eventName 的事件的监听器数组中移除指定的 listener。
on、once创建的监听器都可用off销毁;


import { emitter } from '@/utils/events'function emitTest() {console.log('葬送的芙莉莲');}emitter.on('emitTest',emitTest)emitter.off('emitTest',emitTest)

6、监听EventEmitter的 on、off 事件;

import { EventEmitter } from 'events';export const emitter = new EventEmitter();
// 在将监听器添加到其内部监听器数组之前,EventEmitter 实例将触发自身的 'newListener' 事件。
// 以此来监听 `事件总线` 的添加事件;
emitter.on('newListener', (eventName, listener) => {console.log(eventName, listener,'这是添加');
});
// 同理,监听删除事件
emitter.on('removeListener', (eventName, listener) => {console.log(eventName, listener,'这是删除');
});

7、监听数量相关内容:

  1. 默认监听同一事件名的最大数量为10,若是注册超过10个以上则会抛出警告。
  2. emitter.getMaxListeners() 获取emitter事件总线实例可注册监听器同一事件名的最大数量,默认为10;

  3. 通过emitter.setMaxListeners(8) 来更改限制,传入Infinity(或 0)则表示不限制;【虽然即使限制了,但超出也只是抛出警告,还是会正常注册该监听函数。抛警告是便于防止内存泄漏问题】;另外setMaxListeners跟defaultMaxListeners无关,setMaxListeners 修改了并不会更改 defaultMaxListeners ,简单来说就是2个属性名,set修改的是 _maxListeners 属性值,该属性有值时以 _maxListeners 为优先,没值则是

  4. emitter.defaultMaxListeners 返回默认监听最大数量,但好像没啥用,返回undefined,用getMaxListeners则能拿到官方说的10。
    官方说defaultMaxListeners不要更改!不然会影响所有实例。虽然我验证了下改了也没用,但官方说啥就是啥,你别改就完事了,而且改这个属性也是不规范的做法。

import { EventEmitter } from 'events';
export const emitter = new EventEmitter();console.log(emitter.defaultMaxListeners);// emitter.setMaxListeners(3)console.log(emitter.getMaxListeners());emitter.on('ceshi1',demo)emitter.on('ceshi1',demo)emitter.on('ceshi1',demo)emitter.on('ceshi1',demo)emitter.on('ceshi1',demo)emitter.on('ceshi1',demo)emitter.on('ceshi1',demo)emitter.on('ceshi1',demo)emitter.on('ceshi1',demo)emitter.on('ceshi1',demo)emitter.on('ceshi1',demo) // 默认10个,此时再注册则会报warn提醒你emitter.on('ceshi1',demo)

8、eventNames:返回事件总线里已注册了的所有监听器事件名(eventName)。

类型:eventNames(): Array<string | symbol>;

多次同名注册的也只返回一个eventName给数组。
查看某监听器事件名注册次数看下面的内容 9。


import { emitter } from '@/utils/events'
console.log(emitter.eventNames())

9、listenerCount:获取监听名为 eventName 的事件的监听器数量。

类型:listenerCount(eventName: string | symbol): number;

import { EventEmitter } from 'events';
export const emitter = new EventEmitter();emitter.on('ceshi1',demo)emitter.on('ceshi1',demo)emitter.on('ceshi1',demo)console.log(emitter.listenerCount('ceshi1')); // log: 3

相关文章:

vue3跨组件(多组件)通信:事件总线【Event Bus】

★推荐方案&#xff1a;使用 events npm库&#xff1b; 可用范围&#xff1a;vue、react、angular等任何框架都可使用&#xff1b;且使用方式完全一致&#xff1b; 本文仅介绍、讲解对web页面端项目的常用API&#xff1b;通过events实现事件总线功能&#xff1b; event库概述&a…...

教材管理系统

文章目录 教材管理系统一、系统演示二、项目介绍三、系统部分功能截图四、部分代码展示五、底部获取项目源码&#xff08;9.9&#xffe5;带走&#xff09; 教材管理系统 一、系统演示 教材管理系统 二、项目介绍 语言&#xff1a;nodejs 框架&#xff1a;egg.js、Vue 数据库…...

PV、UV、IP

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言1. PV1.1 PV 计算1.2 PV 的影响因素 2. UV2.1 UV 计算2.2UV 的影响因素 3. IP3.1 IP和UV①UV大于IP②UV小于IP 三者的关系PV 和 UV 前言 PV、UV、IP是我们在运…...

ZigBee学习——在官方例程上实现串口通信

Z-Stack版本为3.0.2 IAR版本为10.10.1 文章目录 一、添加头文件二、定义接收缓冲区三、编写Uart初始化函数四、编写串口回调函数五、函数声明六、函数调用七、可能遇到的问题(function “halUartInit“ has no prototype) 以下所有操作都是在APP层进行&#xff0c;也就是这个文…...

nginx添加lua模块

目录 已安装了nginx&#xff0c;后追加lua模块nginx 重新编译知识参考&#xff1a; 从零安装一、首先需要安装必要的库&#xff08;pcre、zlib、openssl&#xff09;二、安装LUA环境及相关库 &#xff08;LuaJIT、ngx_devel_kit、lua-nginx-module&#xff09;注意&#xff1a;…...

Csapp-chapter3-压栈和弹栈

bp与sp&#xff08;压栈和弹栈&#xff09; 在计算机内部的寄存器组中&#xff0c;有一对寄存器非常有意思&#xff1a;%ebp&#xff0c;%esp 文章目录 bp与sp&#xff08;压栈和弹栈&#xff09;寄存器组示例图%ebp与%esp总结 寄存器组示例图 首先我们应该对于计算机中的寄存…...

Rust入门1——HelloWorld

文章目录 一、HelloWorld二、控制台输入 以最简单的两个Rust程序例子入门Rust。首先需要下载安装Rust&#xff0c;之后在VSCode或Clion中运行Rust需要下载Rust插件 一、HelloWorld fn main(){println!("Hello World!"); }二、控制台输入 use std::io::stdin; fn …...

android中使用Bitmp对象绘制图形

1、引言 你是否还在因为不懂UI设计而不得不去借用别人的图片&#xff0c;甚至使用各种网图作为界面布局的一部分&#xff0c;那么今天就教你使用Bitmap对象去绘制自定义图形&#xff0c;并保存为png格式的图片&#xff0c;须知图片编辑软件本就是程序员开发出来的&#xff0c;我…...

Linux操作系统基础(八):Linux的vi/vim编辑器

文章目录 Linux的vi/vim编辑器 一、vi/vim编辑器介绍 二、打开文件 三、VIM编辑器的三种模式(重点) 四、命令模式相关命令 五、底行模式相关命令 Linux的vi/vim编辑器 一、vi/vim编辑器介绍 vi是visual interface的简称, 是Linux中最经典的文本编辑器 vi的核心设计思想…...

nginx限制网段访问

文章目录 nginx限制网段访问介绍:使用:示例:介绍网段:nginx限制网段访问 介绍: Nginx的deny和allow指令是由ngx_http_access_module模块提供, Nginx安装默认内置了该模块 使用: nginx访问控制模块: 想禁止哪个ip访问就加上deny IP, 想允许哪个ip访问就加上allow…...

Linux开机自动执行自定义脚本或命令

尝试了多种方法&#xff0c;现总结如下&#xff1a; 在用户登录之前自动执行 1. /etc/init.d/rcS 2. /etc/inittab 在用户登录之后自动执行&#xff1a;下述方法&#xff0c;实际尝试发现&#xff0c;之后再输入用户名和密码后才会自动执行。当如果不需要输入用户名或密码时…...

【Linux】 网络编程套接字

目录 预备知识 网络字节序 网络字节序和主机字节序转换的库函数 socket编程接口 socket常见API sockaddr结构 套接字的种类 预备知识 1.在IP数据包头部中&#xff0c;有两个IP地址&#xff0c;分别叫做源IP地址和目的IP地址。 2.端口号&#xff1a;是传输层协议的内容…...

MATLAB矩阵的操作(第二部分)

师从清风 矩阵的创建方法 在MATLAB中&#xff0c;矩阵的创建方法主要有三种&#xff0c;分别是&#xff1a;直接输入法、函数创建法和导入本地文件中的数据。 直接输入法 输入矩阵时要以中括号“[ ]”作为标识符号&#xff0c;矩阵的所有元素必须都在中括号内。 矩阵的同行元…...

基础面试题整理6之Redis

1.Redis的应用场景 Redis支持类型&#xff1a;String、hash、set、zset、list String类型 hash类型 set类型 zset类型 list类型 一般用作缓存&#xff0c;例如 如何同时操作同一功能 2.redis是单线程 Redis服务端(数据操作)是单线程&#xff0c;所以Redis是并发安全的,因…...

MySQL基础查询篇(7)-常用的字符串函数

MySQL数据库是目前广泛应用于各种系统中的一种关系型数据库管理系统。在MySQL中&#xff0c;有许多常见的字符串函数&#xff0c;可以对字符串进行各种处理和操作。本文将介绍MySQL数据库中常用的一些字符串函数&#xff0c;并提供详细示例。 CONCAT函数&#xff1a;用于将两个…...

如何实现视线(目光)的检测与实时跟踪

如何实现视线(目光)的检测与实时跟踪 核心步骤展示说明 找到人脸 检测人脸特征点 根据特征点找到人眼区域 高精度梯度算法检测瞳孔中心 根据眼睛周边特征点计算眼睛中心 瞳孔中心和眼睛中心基于视线模型计算视线方向 视线方向可视化 详细实现与说明&#xff1a; https://stud…...

STM32 FSMC (Flexible static memory controller) 灵活静态内存控制器介绍

文章目录 1. 介绍FSMC2. FSMC特点3. Block示意图4. AHB接口4.1 Supported memories and transactionsGeneral transaction rulesConfiguration registers 5. 外部设备地址映射5.1 NOR/PSRAM地址映射将NOR Flash/PSRAM的支持进行封装 5.2 NAND/PC Card地址映射 1. 介绍FSMC 说到…...

手把手教你开发Python桌面应用-PyQt6图书管理系统-图书信息维护模块UI设计实现

锋哥原创的PyQt6图书管理系统视频教程&#xff1a; PyQt6图书管理系统视频教程 Python桌面开发 Python入门级项目实战 (无废话版) 火爆连载更新中~_哔哩哔哩_bilibiliPyQt6图书管理系统视频教程 Python桌面开发 Python入门级项目实战 (无废话版) 火爆连载更新中~共计24条视频&…...

SpringBoot源码解读与原理分析(六)WebMvc场景的自动装配

文章目录 2.6 WebMvc场景下的自动装配原理2.6.1 WebMvcAutoConfiguration2.6.2 Servlet容器的装配2.6.2.1 EmbeddedTomcat、EmbeddedJetty、EmbeddedUndertow2.6.2.2 BeanPostProcessorsRegistrar(后置处理器的注册器)2.6.2.3 两个定制器的注册 2.6.3 DispatcherServlet的装配2…...

git恢复rebase过程中遇到权限问题和丢失的提交

文章目录 一、检查丢失的提交是否还在 reflog 中二、创建一个新分支来恢复丢失的提交三、处理权限问题四. 使用 git fsck 查找丢失对象1、创建一个新分支来恢复该提交2、检查和合并提交 五. 介绍git中命令reflog 与 fsck1、git reflog2、git fsck使用场景 一、检查丢失的提交是…...

懒人精灵实战:用Lua脚本读写安卓手游内存(以libunity.so为例)

懒人精灵实战&#xff1a;用Lua脚本读写安卓手游内存&#xff08;以libunity.so为例&#xff09; 在移动游戏开发与逆向工程领域&#xff0c;内存读写技术一直是一个既神秘又实用的技能。对于想要深入了解游戏机制或进行自动化测试的开发者来说&#xff0c;掌握这项技术无疑会带…...

STC8H上跑smallRTOS51:从源码下载到多任务调度的完整实战(附避坑指南)

STC8H实战smallRTOS51&#xff1a;从零构建多任务系统的全流程解析 作为一名长期使用STM32的嵌入式开发者&#xff0c;第一次接触STC8H时&#xff0c;裸机编程的局限性让我倍感束缚。当项目复杂度上升&#xff0c;多任务管理成为刚需&#xff0c;我决定在STC8H上移植smallRTOS5…...

如何在Python中正确调用DeepSeek-Reasoner获取思考过程(附完整代码示例)

深度解析&#xff1a;Python调用DeepSeek-Reasoner获取思维链的工程实践 当开发者需要构建具备复杂推理能力的AI应用时&#xff0c;获取模型完整的思考过程&#xff08;Reasoning Content&#xff09;往往比最终答案更有价值。DeepSeek-Reasoner作为专为逻辑推理优化的模型&…...

如何解决健康160抢号难题?智能工具91160-cli让挂号效率提升5倍

如何解决健康160抢号难题&#xff1f;智能工具91160-cli让挂号效率提升5倍 【免费下载链接】91160-cli 健康160全自动挂号脚本 项目地址: https://gitcode.com/gh_mirrors/91/91160-cli 你是否曾遇到预约专家号时页面卡顿&#xff0c;等刷新完成号源已被抢空&#xff1f…...

BERT 模型:自然语言处理的新篇章

BERT模型&#xff1a;自然语言处理的新篇章 在人工智能领域&#xff0c;自然语言处理&#xff08;NLP&#xff09;一直是研究的热点之一。2018年&#xff0c;谷歌推出的BERT模型彻底改变了NLP的发展方向&#xff0c;成为该领域的重要里程碑。BERT&#xff08;Bidirectional En…...

Go的interface空值与类型断言的最佳实践

Go语言中的interface空值与类型断言是开发者经常遇到的核心概念&#xff0c;掌握其最佳实践能显著提升代码的健壮性和可维护性。interface的灵活性使其成为Go多态的重要工具&#xff0c;但空值处理和类型断言的不当使用可能导致运行时错误或逻辑漏洞。本文将深入探讨如何高效处…...

SPI Flash时序参数详解:如何用Synopsys VIP验证Micron芯片的HOLD时序

SPI Flash时序验证实战&#xff1a;Synopsys VIP在Micron芯片HOLD时序分析中的应用 当硬件验证工程师面对SPI Flash芯片时&#xff0c;时序参数的精确验证往往是项目成败的关键。Micron作为主流存储芯片供应商&#xff0c;其SPI Flash产品广泛应用于嵌入式系统和FPGA设计中&…...

别再手动写DSP了!Vivado里用Multiply Adder IP核实现MAC运算的保姆级教程

高效实现MAC运算&#xff1a;Vivado中Multiply Adder IP核的工程实践指南 在FPGA开发中&#xff0c;乘累加&#xff08;MAC&#xff09;运算作为数字信号处理的核心操作&#xff0c;其实现效率直接影响系统性能。传统手写RTL代码不仅耗时&#xff0c;还容易引入时序问题和资源浪…...

【shell】shell实现交互式输入与超时处理

1. Shell脚本交互式输入基础 在Shell脚本编程中&#xff0c;交互式输入是最基础也最常用的功能之一。想象一下这样的场景&#xff1a;你写了一个自动安装软件的脚本&#xff0c;需要用户确认是否继续&#xff1b;或者开发了一个配置工具&#xff0c;需要用户输入IP地址和端口号…...

解密Matplotlib字体机制:为什么你的中文总变成豆腐块?

解密Matplotlib字体机制&#xff1a;为什么你的中文总变成豆腐块&#xff1f; 当你在Python中使用Matplotlib绘制图表时&#xff0c;是否经常遇到这样的场景&#xff1a;精心设计的图表标题和标签&#xff0c;一旦包含中文就变成了令人头疼的"豆腐块"&#xff08;□&…...