我们知道vue3中移除了$on
,$off
和 $once
,所以不提供全局事件总线的能力了。并且官方也推荐使用mitt 或 tiny-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);
上面这两种定义自定义事件的方法,在派发事件时不能传递额外数据,所以用处不大,知识这里总结一下。
往期文章
- 因为原生,选择一家公司(前端如何防笔试作弊)
- 结合开发,带你熟悉package.json与tsconfig.json配置
- 如何优雅的在项目中使用echarts
- 如何优雅的做项目国际化
- 近三个月的排错,原来的憧憬消失喽
- 带你从0开始了解vue3核心(运行时)
- 带你从0开始了解vue3核心(computed, watch)
- 带你从0开始了解vue3核心(响应式)
- 3w+字的后台管理通用功能解决方案送给你
- 入职之前,狂补技术,4w字的前端技术解决方案送给你(vue3 + vite )