原生js如何实现全局事件总线

我们知道vue3中移除了$on$off$once,所以不提供全局事件总线的能力了。并且官方也推荐使用mitttiny-emitter来做事件总线功能。

那么这篇文章就是介绍如何使用js原生提供的自定义事件实现组件间的通信的。即类似于全局事件总线的类库的。

首先我们先了解一下EventTarget。我们可以通过EventTarget显示的创建一个事件目标对象用于提供全局定义和派发事件。

js 复制代码
// 全局事件目标对象
const eventTarget = new EventTarget();
export default eventTarget

类似于使用mitt类库定义全局派发对象。

js 复制代码
import mitt from 'mitt'

const emitter = mitt()
export default emitter

然后我们可以通过CustomEvent来定义一个派发事件对象。注意,我们一般使用全局事件总线发送事件时,都是想要传递一些信息的,我们使用CustomEvent就可以定义一些数据进行传递。

CustomEvent参数

  • 参数一:派发事件的名称,用于事件监听器获取。
  • 参数二:用于提供派发事件的配置。
    • detail:派发时传递的参数。
    • bubbles: 事件是否可以冒泡。这个主要是用于document去做全局派发对象时,可以在任何元素上触发起作用。利用事件冒泡的原理。我们使用EventTarget作为全局派发对象就无所谓了。
    • cancelable: 事件是否可以取消。我们一般可以通过event.cancelable属性来判断当前事件是否可以取消,即通过event.preventDefault()去取消默认行为。
js 复制代码
// 另一个组件派发事件
const customEvent = new CustomEvent("foo", { detail: "详细数据" });
eventTarget.dispatchEvent(customEvent);

类似于mitt中的emit

js 复制代码
emitter.emit('handleIsResponseInput', {
    isDialog: true,
    commentId,
})

然后我们可以使用CustomTarget全局事件目标对象监听addEventListener当前派发的事件,获取派发数据(可以通过event.detail中拿到数据),进行对应的逻辑处理。并且我们可以通过removeEventListener来移除自定义事件。

js 复制代码
const fn = (event: Event) => {
  // event.detail中可以拿到传递的数据。
  console.log("event======", event)
}
eventTarget.addEventListener("foo", fn)

eventTarget.removeEventListener("foo", fn)

类似于mitt中的on

js 复制代码
emitter.on('handleIsResponseInput', (params) => {
  // 点击回复,打开对话框
  dialogVisible.value = params.isDialog
  commentId.value = params.commentId
})

以上就是通过原生js提供的自定义事件API去完成事件派发。如果是简单的使用,我们可以直接这种方式进行组件通信即可。但是在项目中尽量不要使用事件总线进行数据传递,因为使用起来比较混乱。

还有几种方式可以去定义自定义事件:

通过Event去定义一个事件对象

js 复制代码
// 注意:一般我们自定义事件都会传递一些数据,这种不能传递数据的,使用场景不大。
// Event不能传递自定义数据。参数二:bubbles: 是否可冒泡 cancelable: 是否可被取消 composed: 是否会在影子 DOM 根节点之外触发侦听器。(用于具有自定义元素)
const event = new Event("customEvent", {bubbles: true,cancelable: false, composed: false})
document.addEventListener("customEvent", (event) => {
  console.log("event", event)
})
// 触发在定义之后 (需要定义事件冒泡才可以在其他元素上触发。)即bubbles为true
div.dispatchEvent(event)

通过document.createEvent创建一个事件对象,并且通过initEvent()方法去初始化该事件对象 , 用这种方式初始化事件必须是由 Document.createEvent() 方法创建的实例。本方法必须在事件被触发之前调用(用EventTarget.dispatchEvent()调用)。事件一旦被调用,便不再做其他任何事。

js 复制代码
const elem=document.querySelector('#div');

const event=document.createEvent('Event');

// 必须进行初始化,否者无法派发,并且在派发之前初始化
event.initEvent('foo',true,true);

// 监听
document.addEventListener('foo',function(e) {
  console.log(e);
},false);

// 使用目标对象去派发事件,可以是元素节点/事件对象
// div派发的事件,document可以监听到。因为开启了事件冒泡
elem.dispatchEvent(event);

上面这两种定义自定义事件的方法,在派发事件时不能传递额外数据,所以用处不大,知识这里总结一下。

往期文章

专栏文章

相关推荐
小笔学长3 分钟前
调试技巧:使用 debugger 语句
javascript·前端开发·debugger调试·项目调试实战
千里马-horse12 分钟前
TypedArrayOf
开发语言·javascript·c++·node.js·napi
小笔学长20 分钟前
Webpack 配置优化:提高打包速度与质量
前端·项目实战·前端开发·webpack优化·打包性能优化
Hao_Harrision25 分钟前
50天50个小项目 (React19 + Tailwindcss V4) ✨| NotesApp(便签笔记组件)
javascript
优爱蛋白28 分钟前
SCF His Tag 重组蛋白:c-Kit受体信号研究与干细胞培养应用的关键试剂
前端·人工智能·健康医疗
码农水水32 分钟前
京东Java面试被问:系统限流的实现方式
java·开发语言·面试
C_心欲无痕34 分钟前
react - Suspense异步加载组件
前端·react.js·前端框架
JosieBook41 分钟前
【Vue】05 Vue技术——Vue 数据绑定的两种方式:单向绑定、双向绑定
前端·javascript·vue.js
前端小L1 小时前
贪心算法专题(十五):借位与填充的智慧——「单调递增的数字」
javascript·算法·贪心算法
想学后端的前端工程师1 小时前
【浏览器工作原理与性能优化指南:深入理解Web性能】
前端·性能优化