Vue中通过EventBus事件中心进行兄弟节点之间的通信,是一个非常经典的发布订阅模式实现。
前置准备
往Vue实例上添加一个_events属性,属性值是一个对象,用于以键值对的方式,分别存储事件名称,以及存储事件回调函数的数组。
$on、$once、$emit、$off方法是定义在Vue原型上的,所有的Vue实例都可以调用这些方法。
事件中心要运转起来,必须要基于同一个实例来调用这些方法,因为只有这样事件的存储空间才会被共用,事件的发布和订阅才能被串起来。在Vue中使用事件中心的时候,可以全局定义一个Vue实例,专门用于组件通信。
$on
$on方法接收两个参数,第一个参数可能是字符串类型的事件名和数组类型事件名数组,第二个参数是回调函数。
这里用到了递归,如果参数的第一项是数组,就遍历数组,将数组项作为第一个参数,第二个参数不变,递归执行$on方法。直到第一个参数是一个字符串了,就可以接着执行订阅事件的逻辑。
接下来判断当前_events对象里,$on方法的第一个参数作为key,所对应的值是否存在。
- 如果不存在,则先创建一个空数组,然后再往数组中添加回调函数;
- 如果存在,则说明值已经是一个数组类型了,直接往数组中添加回调函数。
$once
$once方法接收两个参数,第一个参数是字符串类型的事件名,第二个参数是回调函数。
内部执行的就是on方法,并且当回调函数执行一次后,再通过off方法移除事件的回调,确保回调函数只执行一次。
在once方法中新创建一个回调函数,作为on方法事件的回调,在新回调函数中执行off方法移除事件的回调,那么新回调函数就是只会被执行一次,在里面执行once的第二个参数就可以了。
$emit
$emit方法接收一个参数,是一个字符串类型的事件名。
根据事件名找到事件名对应的所有的回调函数,然后执行所有的回调函数。
$off
$off方法接收参数是不固定个数的(0、1或2),用于移除事件回调。
- $off():将_events对象赋值为空对象;
- $off([event, …], fn):这里也用到了递归,最后执行off(event, fn),一个一个执行移除指定事件名event和指定fn;
- $off(event, fn):用于移除指定事件名event和指定fn;
- $off(event):用于移除指定事件名event对应所有的fn。