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[]) => void
    emitter.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返回的结果都是false
  const has = emitter2.emit('emitTest','返回false') // 就算on创建过监听函数,off后此时触发不到也是返回false
  const 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 = 0
    emitter.once('test2',function () {
      ++countt
      console.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;

多次同名注册的也只返回一个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

你可能感兴趣的:(前端,javascript,vue,javascript,vue.js,前端)