2

Vue 3 大改了事件绑定机制,事件绑定变成了简单的属性传递,$on$off 也没了,Vue 对象完全失去了 EventBus 的功能。尤大最后安利了一个第三方库,用个 EventBus 发个事件还要第三方库?这也太 low 了吧。

​JavaScript 本来原生就提供了事件绑定机制,前端开发都用了无数遍了,就是 addEventListener 。​addEventListener 是类 EventTarget 的成员方法,我们可以给一个按钮绑定 click 事件,实际上是因为按钮的原型类 HTMLButtonElement 继承自 EventTarget

image

原生的 EventBus

不同于大多数 DOM 原型类,EventTarget 可以直接 new,但是仅在较新的浏览器中才支持。我们也不需要用元素这种重量级的东西。从上面的截图可以看到,Node 就继承自 EventTarget,所以所有 DOM 节点都有 addEventListener,这里推荐一种足够轻量级的节点:注释

对于浏览器渲染引擎来说,注释就是一段解释性的文字,没有任何作用,纯粹给开发者看的。但是注释写在 HTML 脚本中,它仍然是一个节点,有自己的原型类 Comment,并且继承自 Node

Comment 类可以直接 new,也可以使用比较老的但是兼容性更好的方式 document.createComment,它强制要求一个参数,是注释的内容。你可以写一些描述性的信息,如果没什么可说的,直接用空字符串也可以。

const myEventBus = document.createComment('my-event-bus');

有了 EventBus 实例​就可以触发事件了。触发事件使用 dispatchEventdispatchEvent 接收一个 Event 对象,但是通常的 Event 对象不能传递用户的自定义数据,这时可以用 CustomEvent,它的 detail 属性可以存储任意数据。

myEventBus.dispatchEvent(new CustomEvent('event-name', { detail: 'event-data' }));

需要注意的是,虽然 IE9+ 都支持 CustomEvent,但是包括 IE11 在内都不支持 new CustomEvent。虽然可以用 document.createEvent 但是操作复杂,建议用一下 Polyfill

不过话说 Vue 3 都不想支持 IE 了我们纠结那么多干嘛。。。

最后就可以接收事件了

myEventBus.addEventListener('event-name', ({ detail }) => {
    console.log(detail); // => event-data
});

新版浏览器中 addEventListener 还可以使用 { once: true } 实现单次绑定

关于调试

项目复杂之后,绑定的事件会越来越多,还可能出现绑定过后忘了解绑的bug。如果我想看看 myEventBus 上面绑定了哪些事件应该怎样看呢?

myEventBus 是一个 DOM 节点,所以它可以用浏览器的元素查看器调试

首先将其追加到 DOM 树上。往页面中添加注释通常不会对原页面产生影响。

document.appendChild(myEventBus)

这时就可以在 DOM 树的末尾找到这个注释节点,可以直接查看

image.png

你还能找到绑定事件代码的位置,还可以直接删除某个事件绑定。是不是很方便?


CarterLi
1.3k 声望102 粉丝