Libon

浏览器内置的 "EventBus"

3Mins #JavaScript
学习浏览器中内置的原生 EventBus 概念与使用方法

ToC

对于已经有一些编程经验的人来说,对 “EventBus” 的概念肯定不陌生,从 Vue2 中使用 new Vue 再到 Vue3 中官方推荐的 mitt,还有 node 中的 events 模块,都是 EventBus 这个概念的实践,但其实我们每个前端程序员从很早就开始接触这个概念了,只是那时我们还不知道叫这个名字(就像在学设计模式的时候也会恍惚间发现,原来我那次优化后的代码叫xxx模式呀),它就是 DOM 中的事件系统,同时事件系统也是一个标准的发布订阅模式。addEventListener 对应着 on 方法,removeEventListener 则对应着 off 方法。

1
<button id="button">button</button>
2
3
<script>
4
const button = document.querySelector('#button')
5
6
button.addEventListener('click', alert)
7
8
button.removeEventListener('click', alert)
9
</script>

以上示例代码将事件监听器对象限制为 button 元素,如果我们在框架开发中想要使用 EventBus 来实现夸组件通信的话,我们就可以将事件监听器对象调整为 document 或是 window

1
<!-- 组件A -->
2
<button id="button">button</button>
3
4
<script>
5
const button = document.querySelector('#button')
6
7
function onButtonClick() {
8
document.dispatchEvent(new CustomEvent('toggle'))
9
}
10
2 collapsed lines
11
button.addEventListener('click', onButtonClick)
12
</script>
1
<!-- 组件B -->
2
<output id="output"></output>
3
4
<script>
5
const output = document.querySelector('#output')
6
7
let count = 0
8
9
function onToggle() {
10
output.textContent = ++count
4 collapsed lines
11
}
12
13
document.addEventListener('toggle', onToggle)
14
</script>

以下示例模拟了上述行为:

是的,我们实际上是使用了 dispatchEvent 加上 CustomEvent 来完成了自定义事件触发的过程,使用原生的 addEventListener 来完成添加观察者的行为。

使用原生方案实现的一个好处是不需要引入额外的库,不会增加项目体积,同时还兼容各种框架,但缺点是需要手动维护事件,并且只能在非SSR的情况下使用,除此之外,CustomEvent 在 IE 上使用也会有兼容性问题(万恶的IE)。

触发其他组件按钮中的方法

其实平时在框架开发中,偶尔也会遇到调用其他组件的方法,比如说A组件内的一个按钮点击以后需要触发和B组件中某个按钮点击以后执行的事件,我们就可以利用 HTML 中 <label /> 元素的 for 属性与目标按钮的 id 属性绑定:

1
<!-- 组件A -->
2
<label for="button">
3
<!-- 需要注意的是,如果这里面不能使用 button 标签,否则 for 属性则会失效 -->
4
<!-- 因为 label 默认会找最近的表单元素进行关联,如果内部有表单则不会使用 for 去寻找外部表单 -->
5
<!-- 同时 组件B 中与 label 所关联的元素也需要是 <button /> 或 <input /> -->
6
<span>组件A的按钮</span>
7
</label>
1
<!-- 组件B -->
2
<button id="button" onclick="javascript:alert(1);">组件B的组件</button>

以下示例模拟了上述行为:

以上。


CD ..