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、监听数量相关内容:
- 默认监听同一事件名的最大数量为10,若是注册超过10个以上则会抛出警告。
-
emitter.getMaxListeners() 获取emitter事件总线实例可注册监听器同一事件名的最大数量,默认为10;
-
通过emitter.setMaxListeners(8) 来更改限制,传入
Infinity(或0)则表示不限制;【虽然即使限制了,但超出也只是抛出警告,还是会正常注册该监听函数。抛警告是便于防止内存泄漏问题】;另外setMaxListeners跟defaultMaxListeners无关,setMaxListeners 修改了并不会更改 defaultMaxListeners ,简单来说就是2个属性名,set修改的是 _maxListeners 属性值,该属性有值时以 _maxListeners 为优先,没值则是 -
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】
★推荐方案:使用 events npm库; 可用范围:vue、react、angular等任何框架都可使用;且使用方式完全一致; 本文仅介绍、讲解对web页面端项目的常用API;通过events实现事件总线功能; event库概述&a…...
教材管理系统
文章目录 教材管理系统一、系统演示二、项目介绍三、系统部分功能截图四、部分代码展示五、底部获取项目源码(9.9¥带走) 教材管理系统 一、系统演示 教材管理系统 二、项目介绍 语言:nodejs 框架:egg.js、Vue 数据库…...
PV、UV、IP
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言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层进行,也就是这个文…...
nginx添加lua模块
目录 已安装了nginx,后追加lua模块nginx 重新编译知识参考: 从零安装一、首先需要安装必要的库(pcre、zlib、openssl)二、安装LUA环境及相关库 (LuaJIT、ngx_devel_kit、lua-nginx-module)注意:…...
Csapp-chapter3-压栈和弹栈
bp与sp(压栈和弹栈) 在计算机内部的寄存器组中,有一对寄存器非常有意思:%ebp,%esp 文章目录 bp与sp(压栈和弹栈)寄存器组示例图%ebp与%esp总结 寄存器组示例图 首先我们应该对于计算机中的寄存…...
Rust入门1——HelloWorld
文章目录 一、HelloWorld二、控制台输入 以最简单的两个Rust程序例子入门Rust。首先需要下载安装Rust,之后在VSCode或Clion中运行Rust需要下载Rust插件 一、HelloWorld fn main(){println!("Hello World!"); }二、控制台输入 use std::io::stdin; fn …...
android中使用Bitmp对象绘制图形
1、引言 你是否还在因为不懂UI设计而不得不去借用别人的图片,甚至使用各种网图作为界面布局的一部分,那么今天就教你使用Bitmap对象去绘制自定义图形,并保存为png格式的图片,须知图片编辑软件本就是程序员开发出来的,我…...
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开机自动执行自定义脚本或命令
尝试了多种方法,现总结如下: 在用户登录之前自动执行 1. /etc/init.d/rcS 2. /etc/inittab 在用户登录之后自动执行:下述方法,实际尝试发现,之后再输入用户名和密码后才会自动执行。当如果不需要输入用户名或密码时…...
【Linux】 网络编程套接字
目录 预备知识 网络字节序 网络字节序和主机字节序转换的库函数 socket编程接口 socket常见API sockaddr结构 套接字的种类 预备知识 1.在IP数据包头部中,有两个IP地址,分别叫做源IP地址和目的IP地址。 2.端口号:是传输层协议的内容…...
MATLAB矩阵的操作(第二部分)
师从清风 矩阵的创建方法 在MATLAB中,矩阵的创建方法主要有三种,分别是:直接输入法、函数创建法和导入本地文件中的数据。 直接输入法 输入矩阵时要以中括号“[ ]”作为标识符号,矩阵的所有元素必须都在中括号内。 矩阵的同行元…...
基础面试题整理6之Redis
1.Redis的应用场景 Redis支持类型:String、hash、set、zset、list String类型 hash类型 set类型 zset类型 list类型 一般用作缓存,例如 如何同时操作同一功能 2.redis是单线程 Redis服务端(数据操作)是单线程,所以Redis是并发安全的,因…...
MySQL基础查询篇(7)-常用的字符串函数
MySQL数据库是目前广泛应用于各种系统中的一种关系型数据库管理系统。在MySQL中,有许多常见的字符串函数,可以对字符串进行各种处理和操作。本文将介绍MySQL数据库中常用的一些字符串函数,并提供详细示例。 CONCAT函数:用于将两个…...
如何实现视线(目光)的检测与实时跟踪
如何实现视线(目光)的检测与实时跟踪 核心步骤展示说明 找到人脸 检测人脸特征点 根据特征点找到人眼区域 高精度梯度算法检测瞳孔中心 根据眼睛周边特征点计算眼睛中心 瞳孔中心和眼睛中心基于视线模型计算视线方向 视线方向可视化 详细实现与说明: 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图书管理系统视频教程: 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为例)
懒人精灵实战:用Lua脚本读写安卓手游内存(以libunity.so为例) 在移动游戏开发与逆向工程领域,内存读写技术一直是一个既神秘又实用的技能。对于想要深入了解游戏机制或进行自动化测试的开发者来说,掌握这项技术无疑会带…...
STC8H上跑smallRTOS51:从源码下载到多任务调度的完整实战(附避坑指南)
STC8H实战smallRTOS51:从零构建多任务系统的全流程解析 作为一名长期使用STM32的嵌入式开发者,第一次接触STC8H时,裸机编程的局限性让我倍感束缚。当项目复杂度上升,多任务管理成为刚需,我决定在STC8H上移植smallRTOS5…...
如何在Python中正确调用DeepSeek-Reasoner获取思考过程(附完整代码示例)
深度解析:Python调用DeepSeek-Reasoner获取思维链的工程实践 当开发者需要构建具备复杂推理能力的AI应用时,获取模型完整的思考过程(Reasoning Content)往往比最终答案更有价值。DeepSeek-Reasoner作为专为逻辑推理优化的模型&…...
如何解决健康160抢号难题?智能工具91160-cli让挂号效率提升5倍
如何解决健康160抢号难题?智能工具91160-cli让挂号效率提升5倍 【免费下载链接】91160-cli 健康160全自动挂号脚本 项目地址: https://gitcode.com/gh_mirrors/91/91160-cli 你是否曾遇到预约专家号时页面卡顿,等刷新完成号源已被抢空?…...
BERT 模型:自然语言处理的新篇章
BERT模型:自然语言处理的新篇章 在人工智能领域,自然语言处理(NLP)一直是研究的热点之一。2018年,谷歌推出的BERT模型彻底改变了NLP的发展方向,成为该领域的重要里程碑。BERT(Bidirectional En…...
Go的interface空值与类型断言的最佳实践
Go语言中的interface空值与类型断言是开发者经常遇到的核心概念,掌握其最佳实践能显著提升代码的健壮性和可维护性。interface的灵活性使其成为Go多态的重要工具,但空值处理和类型断言的不当使用可能导致运行时错误或逻辑漏洞。本文将深入探讨如何高效处…...
SPI Flash时序参数详解:如何用Synopsys VIP验证Micron芯片的HOLD时序
SPI Flash时序验证实战:Synopsys VIP在Micron芯片HOLD时序分析中的应用 当硬件验证工程师面对SPI Flash芯片时,时序参数的精确验证往往是项目成败的关键。Micron作为主流存储芯片供应商,其SPI Flash产品广泛应用于嵌入式系统和FPGA设计中&…...
别再手动写DSP了!Vivado里用Multiply Adder IP核实现MAC运算的保姆级教程
高效实现MAC运算:Vivado中Multiply Adder IP核的工程实践指南 在FPGA开发中,乘累加(MAC)运算作为数字信号处理的核心操作,其实现效率直接影响系统性能。传统手写RTL代码不仅耗时,还容易引入时序问题和资源浪…...
【shell】shell实现交互式输入与超时处理
1. Shell脚本交互式输入基础 在Shell脚本编程中,交互式输入是最基础也最常用的功能之一。想象一下这样的场景:你写了一个自动安装软件的脚本,需要用户确认是否继续;或者开发了一个配置工具,需要用户输入IP地址和端口号…...
解密Matplotlib字体机制:为什么你的中文总变成豆腐块?
解密Matplotlib字体机制:为什么你的中文总变成豆腐块? 当你在Python中使用Matplotlib绘制图表时,是否经常遇到这样的场景:精心设计的图表标题和标签,一旦包含中文就变成了令人头疼的"豆腐块"(□&…...
