原生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);

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

往期文章

专栏文章

相关推荐
无咎.lsy2 分钟前
vue之vuex的使用及举例
前端·javascript·vue.js
fishmemory7sec10 分钟前
Electron 主进程与渲染进程、预加载preload.js
前端·javascript·electron
fishmemory7sec12 分钟前
Electron 使⽤ electron-builder 打包应用
前端·javascript·electron
豆豆1 小时前
为什么用PageAdmin CMS建设网站?
服务器·开发语言·前端·php·软件构建
JUNAI_Strive_ving1 小时前
番茄小说逆向爬取
javascript·python
看到请催我学习2 小时前
如何实现两个标签页之间的通信
javascript·css·typescript·node.js·html5
twins35202 小时前
解决Vue应用中遇到路由刷新后出现 404 错误
前端·javascript·vue.js
邵泽明2 小时前
面试知识储备-多线程
java·面试·职场和发展
qiyi.sky2 小时前
JavaWeb——Vue组件库Element(3/6):常见组件:Dialog对话框、Form表单(介绍、使用、实际效果)
前端·javascript·vue.js
煸橙干儿~~2 小时前
分析JS Crash(进程崩溃)
java·前端·javascript