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

自定义事件总线

文章目录

    • 什么是自定义事件总线
    • 具体实现
      • 思路分析
      • 定义结构
      • 实现 on
      • 实现 emit
      • 实现 off
    • 源码

什么是自定义事件总线

  1. 自定义事件总线属于一种观察着模式,其中包括三个角色
  2. 发布者(Publisher):发出事件(Event)
  3. 订阅者(Subscriber):订阅事件(Event),并且会进行响应(Handler)
  4. 事件总线(EvnetBus):无论是发布者还是订阅者都是通过事件总线作为中台的

具体实现

思路分析

  1. 事件总线相信大家都用过或者听过,特别是在 vue2 中,这就是一种组件传值的方式,轻量又简单

  2. 从使用上来说,通过 on 监听事件,同时可以使用 emit 来发送事件,当然也可也通过 off 来取消事件

  3. 使用还是非常简单的,但是怎么才能实现 emit 触发 on 监听的呢,竟然要触发的话,首先我是不是需要有一个地方可以存储这个通过 on 监听的方法呢?存储了之后,就是使用,emit 实际就是通过参数找到对应的存储方法,然后我们帮他手动调用一下

  4. 所以基于这一点,我们就可以得到三个点,on、store、emit,如图:

    在这里插入图片描述

定义结构

  1. 根据上面的分析,我们可以选用 class 的形式来实现,

  2. 其次我们还需要 on emit off 三个方法,如下:

    class JcEventBus{constructor() {}on(){}emit(){}off(){}
    }
    
  3. 在这之中,我们就按照分析,确定一下 store,在 class 结构中,可以 this 访问数据和方法,所以在 JcEventBus 初始化时,就可以定义一个变量来存储后续的方法,而可以通过一个字符串准确存储和取出的话,对象和map都可以,但是这里对象会更加好操作,所以改造后 constructor 代码如下:

    constructor() {this.eventBus = {}
    }
    

实现 on

  1. on 方法一般是有两个参数的,我们可以写出基础的函数结构,如下:

    on(eventName, callback){}
    
  2. 我们不妨在思考一下,有时候这个回调函数的this,可能需要我们来指定,方便在函数内部使用 this,所以为了实现这一点,一般会给 callback 传递一个普通函数而非匿名函数,同时应该有第三个参数来接受这个 this,如下:

    on(eventName, callback, ctx){}
    
  3. 确定好参数之后,我们来进行一下具体的实现,首先假设监听的名称为 foo,而且监听的函数有时候可能不止一个,而存储多个函数我们可以想到什么,数组,利用数组来实现存储这些函数,需要用的时候在找到对应的函数进行执行即可,确定好这一点之后,我们要做的就是以 eventName 为 key,callback 存储在数组中为 value,{ foo: [fn1,fn2…] },代码如下:

    on(eventName, callback, ctx){// 如果不存在则初始化为空数组const handles = this.eventBus[eventName] || []// 传递一个对象,同时保存 执行的函数 和 thishandles.push({ callback, ctx })// 存储在 store 中this.eventBus[eventName] = handles
    }
    
  4. 我们来通过实例化 JcEventBus 来进行测试一下,看看是否真的存入了,测试代码如下:

    eventBus.on('foo',function (...payload) {console.log('foo 函数,参数为:', payload)},obj
    )eventBus.on('bar',function (...payload) {console.log('bar 函数,参数为:', payload)},obj
    )console.log(eventBus.eventBus)
    
  5. 输出如图:

    在这里插入图片描述

实现 emit

  1. emit 要做的事件也非常简单,传递事件名称和参数即可,因此基础的函数结构如下:

    emit(eventName, ...payload){}
    
  2. 参数可能会有多个,使用剩余参数来接收,这个方法,第一步就是要查找有没有这个方法,如果有,就执行这个事件名称上绑定的所有函数,代码如下:

    emit(eventName, ...payload) {const handles = this.eventBus[eventName]if (!handles || !handles.length) returnhandles.forEach(handle => {// 使用 apply 绑定 thishandle.callback.apply(handle.ctx, payload)})
    }
    
  3. 这个应该非常简单吧,直接上测试代码。如下:

    const eventBus = new JcEventBus()const obj = { name: 'coderjc' }eventBus.on('foo',function (...payload) {console.log('foo1 函数,参数为:', payload, this)},obj
    )eventBus.on('foo',function (...payload) {console.log('foo2 函数,参数为:', payload)},obj
    )eventBus.emit('foo', 1, 2, 3)
    
  4. 结果如图:

    在这里插入图片描述

实现 off

  1. off 类似于 removeEventListener 这个方法,也是事件名 + 函数,即可取消,所以函数基础结构如下:

    off(eventName, callback){}
    
  2. 然后就是通过事件名称找到这个数组,在这个数组里面找到对应的函数进行删除即可,不过这里会会有一点细节需要注意,比如一个函数被存储了多次的情况下,当然这个你可以在存储的时候就拦截,避免重复,但是我们这里没有,所以如果删除就要删除多个,而这个删除可能有部分的朋友们就会想到遍历,全等判断,然后删除就行吗,这个也可以,但是可能需要多一点的操作,我们先看看这个思路删除会有什么结果,我写了一个demo,如下:

    // 这里用数字代替函数
    const arr = [1, 2, 2, 4, 5, 6]
    const val = 2for (let i = 0; i < arr.length; i++) {if (arr[i] === val) {// 删除arr.splice(i, 1)}
    }
    console.log(arr)
    
  3. 结果如图:

    在这里插入图片描述

  4. 不知道发现了没有,只删除了其中的一个2,还有一个没有删除,这是因为 splice 方法删除之后,原数组的长度就-1了,此时原来索引为2的数组就会变成索引为1,而 i 的值又没有同步的 -1,就会直接跳过,所以就是这个结果了所以解决方法很简单,同时 i-1 即可,当然还是有其他方法的,都是非常简单的

  5. 我这里就直接过滤数组重新赋值了,如下:

    off(eventName, callback){const handles = this.eventBus[eventName]if (!handles || !handles.length) returnthis.eventBus[eventName] = handles.filter(handle => handle.callback !== callback)
    }
    
  6. 来看看是不是真的有用,测试代码如下:

    const eventBus = new JcEventBus()function foo(...payload) {console.log('foo1 函数,参数为:', payload)
    }eventBus.on('foo', foo)eventBus.on('foo', function (...payload) {console.log('foo2 函数,参数为:', payload)
    })// 移除
    eventBus.off('foo', foo)eventBus.emit('foo', 1, 2, 3)
    
  7. 结果如图:

    在这里插入图片描述

源码

当然了,最后我是加了一些对于参数的类型判断,非常简单,就不单独介绍了

function _verifyType(eventName = null, callback = null) {if (eventName && typeof eventName !== 'string') {throw new Error('eventName must be a string')}if (callback && typeof callback !== 'function') {throw new Error('callback must be a function')}
}class JcEventBus {constructor() {this.eventBus = {}}on(eventName, callback, ctx) {_verifyType(eventName, callback)const handles = this.eventBus[eventName] || []handles.push({ callback, ctx })this.eventBus[eventName] = handles}off(eventName, callback) {_verifyType(eventName, callback)const handles = this.eventBus[eventName]if (!handles || !handles.length) returnthis.eventBus[eventName] = handles.filter(handle => handle.callback !== callback)}emit(eventName, ...payload) {_verifyType(eventName)const handles = this.eventBus[eventName]if (!handles || !handles.length) returnhandles.forEach(handle => {handle.callback.apply(handle.ctx, payload)})}
}

相关文章:

自定义事件总线

文章目录 什么是自定义事件总线具体实现思路分析定义结构实现 on实现 emit实现 off 源码 什么是自定义事件总线 自定义事件总线属于一种观察着模式&#xff0c;其中包括三个角色发布者&#xff08;Publisher&#xff09;&#xff1a;发出事件&#xff08;Event&#xff09;订阅…...

212.【2023年华为OD机试真题(C卷)】堆内存申请(排序和贪心算法-JavaPythonC++JS实现)

🚀点击这里可直接跳转到本专栏,可查阅顶置最新的华为OD机试宝典~ 本专栏所有题目均包含优质解题思路,高质量解题代码(Java&Python&C++&JS分别实现),详细代码讲解,助你深入学习,深度掌握! 文章目录 一. 题目-堆内存申请二.解题思路三.题解代码Python题解代…...

Flink Watermark和时间语义

Flink 中的时间语义 时间语义&#xff1a; EventTime&#xff1a;事件创建时间&#xff1b;Ingestion Time&#xff1a;数据进入Flink的时间&#xff1b;Processing Time&#xff1a;执行操作算子的本地系统时间&#xff0c;与机器无关。不同的时间语义有不同的应用场合&#x…...

HarmonyOS UI框架简介

HarmonyOS UI框架介绍 HarmonyOSUI框架是一个用于构建跨设备应用的开发框架&#xff0c;它属于HarmonyOS系统架构的上层框架。该框架通过提供一系列的开发模型、声明式UI范式、系统API等&#xff0c;帮助开发者更高效地构建用户界面。 在HarmonyOSUI框架中&#xff0c;开发语…...

编程羔手解决Maven引入多个版本的依赖包,导致包冲突了

最近升级了些依赖发现有个hutool的方法老报错&#xff0c;java.lang.NoSuchMethodError: cn.hutool.core.util.ObjectUtil.defaultIfNull(Ljava/lang/Object;Ljava/util/function/Supplier;) 在 Maven 项目中&#xff0c;当不同的依赖模块引入 Hutool 的不同版本时&#xff0c…...

C#,入门教程(08)——基本数据类型及使用的基础知识

上一篇&#xff1a; C#&#xff0c;入门教程(07)——软件项目的源文件与目录结构https://blog.csdn.net/beijinghorn/article/details/124139947 数据类型用于指定数据体&#xff08;DataEntity&#xff0c;包括但不限于类或结构体的属性、变量、常量、函数返回值&#xff09;…...

分类预测 | Matlab实现DBO-SVM蜣螂算法优化支持向量机多特征分类预测

分类预测 | Matlab实现DBO-SVM蜣螂算法优化支持向量机多特征分类预测 目录 分类预测 | Matlab实现DBO-SVM蜣螂算法优化支持向量机多特征分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现DBO-SVM蜣螂算法优化支持向量机多特征分类预测&#xff08;完整…...

计算机二级Python选择题考点——公共基础部分

计算机完成一条指令所花费的时间称为一个指令周期。(指令周期越短&#xff0c;指令执行就越快)顺序程序不具有并发性。(具有顺序性、封闭性和可再现性)结构化程序设计强调程序的易读性。系统软件&#xff1a;操作系统、编译程序、数据库管理系统 应用软件&#xff1a;杀毒软件在…...

《微机原理与应用》期末考试题库(附答案解析)

第1章 微型计算机概述 1.微型计算机的硬件系统包括___A _____。 A&#xff0e;控制器、运算器、存储器和输入输出设备 B&#xff0e;控制器、主机、键盘和显示器 C&#xff0e;主机、电源、CPU和输入输出 D&#xff0e;CPU、键盘、显示器和打印机 2.微处…...

如何在Android Glide中结合使用CenterCrop和自定义圆角变换(图片部分圆角矩形)

如何在Android Glide中结合使用CenterCrop和自定义圆角变换&#xff08;图片部分圆角矩形&#xff09; 在Android开发中&#xff0c;使用Glide加载图片时&#xff0c;我们经常需要对图片进行特定的处理&#xff0c;比如裁剪和圆角变换&#xff0c;特别是一些设计稿&#xff0c;…...

华为机考-手拍球游戏

【手拍手计算次数和总数】游戏规则&#xff1a;左手和右手拍球初始数为0&#xff0c;首先左手第一次拍球数1下&#xff0c;右手拍球1下&#xff0c;接下来左手在拍球时是上一次左手上一次右手的总和&#xff0c;右手也是上一次左手上一次右手拍球的总和&#xff0c;最后拍球总数…...

【线上问题】两台服务器的时间不一致导致jwt解析错误

目录 一、问题描述二、解决方法 一、问题描述 1.线上生产问题&#xff0c;本地和测试环境均无问题 2.本地和测试由于网关和登录服务均在同一台机器 3.线上的登录服务和网关部署不在一起&#xff0c;登录服务的时间正常&#xff0c;网关服务的服务器时间比实际快5秒 4.登录服务j…...

58.网游逆向分析与插件开发-游戏增加自动化助手接口-游戏菜单文字资源读取的逆向分析

内容来源于&#xff1a;易道云信息技术研究院VIP课 之前的内容&#xff1a;接管游戏的自动药水设定功能-CSDN博客 码云地址&#xff08;master分支&#xff09;&#xff1a;https://gitee.com/dye_your_fingers/sro_-ex.git 码云版本号&#xff1a;34b9c1d43b512d0b4a3c395b…...

Vue-2、初识Vue

1、helloword小案列 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>初始Vue</title><!--引入vue--><script type"text/javascript" src"https://cdn.jsdelivr.n…...

机器学习项目标记图像数据 - 安装LabelImg及功能介绍

什么是LabelImg&#xff1f; LabelImg 是一款流行的图像标注工具&#xff0c;主要用于计算机视觉领域。它允许用户为机器学习项目标记图像数据&#xff0c;特别是用于训练目标检测模型。 如何安装LabelImg pip install PyQt5 pip install pyqt5-tools pip install lxml pip …...

12.15 log 122.买卖股票的最佳时机 II,55. 跳跃游戏

122.买卖股票的最佳时机 II class Solution { public:int maxProfit(vector<int>& prices) {int result0;for(int i0;i<prices.size();i){if(i>0&&prices[i]-prices[i-1]>0){resultprices[i]-prices[i-1];}}return result;} }; 这道题贪心贪的时每…...

Redis - 挖矿病毒 db0 库 backup 反复出现解决方案

问题描述 腾讯云的服务器&#xff0c;使用 Docker 部署了 Redis 之后&#xff0c;发现 DB0 中总是出现 4 条 key&#xff0c;分别是 backup01backup02backup03backup04 而自己每次存入 db0 中的数据过一会就会被无缘无故删除掉。 原因分析 挖矿病毒 解决方案 在启动的时候…...

LiveGBS流媒体平台GB/T28181常见问题-国标编号是什么设备编号和通道国标编号标记唯一的摄像头|视频|镜头通道

LiveGBS国标GB28181中国标编号是什么设备编号和通道国标编号标记唯一的摄像头|视频|镜头通道 1、什么是国标编号&#xff1f;2、国标设备ID和通道ID3、ID 统一编码规则4、搭建GB28181视频直播平台 1、什么是国标编号&#xff1f; 国标GB28181对接过程中&#xff0c;可能有的小…...

Unity ShaderGraph 技能冷却转圈效果

Unity ShaderGraph 技能冷却转圈效果 前言项目场景布置代码编写ShaderGraph 连线总结 参考 前言 遇到一个需求&#xff0c;要展示技能冷却的圆形遮罩效果。 项目 场景布置 代码编写 Shader核心的就两句 // 将uv坐标系的原点移到纹理中心 float2 uv i.uv - float2(0.5, 0…...

C++上位软件通过Snap7开源库访问西门子S7-1200/S7-1500数据块的方法

前言 本人一直从事C上位软件开发工作较多&#xff0c;在之前的项目中通过C访问西门子PLC S7-200/S7-1200/S7-1500并进行数据交互的应用中一直使用的是ModbusTCP/ModbusRTU协议进行。Modbus上位开源库采用的LibModbus。经过实际应用发现Modbus开源库单次发送和接受的数据不能超过…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

什么是EULA和DPA

文章目录 EULA&#xff08;End User License Agreement&#xff09;DPA&#xff08;Data Protection Agreement&#xff09;一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA&#xff08;End User License Agreement&#xff09; 定义&#xff1a; EULA即…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...