Vue 3 大改了事件绑定机制,事件绑定变成了简单的属性传递,$on
、$off
也没了,Vue 对象完全失去了 EventBus 的功能。尤大最后安利了一个第三方库,用个 EventBus 发个事件还要第三方库?这也太 low 了吧。
JavaScript 本来原生就提供了事件绑定机制,前端开发都用了无数遍了,就是 addEventListener 。addEventListener 是类 EventTarget 的成员方法,我们可以给一个按钮绑定 click
事件,实际上是因为按钮的原型类 HTMLButtonElement
继承自 EventTarget
原生的 EventBus
不同于大多数 DOM 原型类,EventTarget 可以直接 new
,但是仅在较新的浏览器中才支持。我们也不需要用元素这种重量级的东西。从上面的截图可以看到,Node
就继承自 EventTarget
,所以所有 DOM 节点都有 addEventListener
,这里推荐一种足够轻量级的节点:注释
对于浏览器渲染引擎来说,注释就是一段解释性的文字,没有任何作用,纯粹给开发者看的。但是注释写在 HTML 脚本中,它仍然是一个节点,有自己的原型类 Comment,并且继承自 Node
。
Comment
类可以直接 new
,也可以使用比较老的但是兼容性更好的方式 document.createComment
,它强制要求一个参数,是注释的内容。你可以写一些描述性的信息,如果没什么可说的,直接用空字符串也可以。
const myEventBus = document.createComment('my-event-bus');
有了 EventBus 实例就可以触发事件了。触发事件使用 dispatchEvent。dispatchEvent
接收一个 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 树的末尾找到这个注释节点,可以直接查看
你还能找到绑定事件代码的位置,还可以直接删除某个事件绑定。是不是很方便?
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。