开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情
什么是EventBus
EventBus 又称为事件总线。在Vue中可以使用 EventBus 来作为沟通桥梁的概念,就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所以组件都可以上下平行地通知其他组件,但也就是太方便所以若使用不慎,就会造成难以维护的灾难,因此才需要更完善的Vuex作为状态管理中心,将通知的概念上升到共享状态层次。
在vue中我们有时候为了在关系很远的组件中传递数据,这时就会用到事件总线。我们只需要在需要接受数据的组件中监听定义的事件名称,然后在指定回调函数。在传数据的组件中发射对应事件名的事件,并携带数据,这时候回调函数就会被执行,然后就可以获取到指定的数据了。相对于vuex来说,事件总线更方便。
介绍了这么多,我们也知道了事件总线的三个功能,分别是
-
on, 监听事件
-
emit,发射事件
-
off, 移除事件
首先,我们要写一个工具类,我们得先把一些功能和变量定义好。
class EventBus {
constructor() {
this.fns = new Map()
}
emit(eventName, payload) {
}
on(eventName, callback) {
}
off(eventName, callback) {
}
}
tips: 这里用到了map来存储事件名称和对应的回调函数,考虑到一个事件对应不止一个回调函数,则用数组来存储。
接着,我们来一个一个实现对应的功能。
实现on函数
参数接收: 事件名称,回调函数。
实现思路: 先从map对象中get当前事件名称,看是否已经有值。若没有值,则初始化为空数组,然后往数组里push回调函数;若有值,则判断是否已经存在。最后就是更新map的key为事件名称对应的值
on(eventName, callback) {
testArg(eventName, 'string')
testArg(callback, 'function')
// 获取事件名称对应的函数数组
let fnArray = this.fns.get(eventName)
// 第一次
if (fnArray === null || fnArray === undefined) {
fnArray = []
fnArray.push(callback)
} else {
fnArray.indexOf(callback) === -1 ? fnArray.push(callback) : null
}
this.fns.set(eventName, fnArray)
}
这里封装了一个参数校验的函数,实现如下
function testArg(args, type) {
if (typeof args !== type) {
throw Error(`the ${args} must be ${type}!`)
}
}
实现emit函数
参数接收: 事件名称,参数。
实现思路: 从map中获取当前事件名称对应的函数数组,然后执行数组中的函数并传递参数。
emit(eventName, payload) {
testArg(eventName, 'string')
let fnArray = this.fns.get(eventName)
if (fnArray === undefined || fnArray === null || fnArray.length === 0) {
console.log(`${eventName} 事件没有监听函数!!!`)
return
}
fnArray.forEach((fn) => {
fn.call(this, payload)
})
}
实现off函数
参数接收: 事件名称,回调函数。
实现思路: 从map中获取当前事件名称对应的函数数组,然后看是否存在要移除的函数,最后执行对应的操作。
off(eventName, callback) {
testArg(eventName, 'string')
testArg(callback, 'function')
let fnArray = this.fns.get(eventName)
if (fnArray === undefined || fnArray === null || fnArray.length === 0) {
console.log(`${eventName} 事件没有监听函数!!!`)
return
}
const index = fnArray.indexOf(callback)
if (index === -1) {
console.log(`${eventName} 事件没有监听函数!!!`)
return
} else {
fnArray.splice(index, 1)
}
this.fns.set(eventName, fnArray)
}
好了,我们已经实现了三个功能,我们来写一段代码测试一下
const EventBus = require('./index')
function test1() {
console.log('test1')
}
function test2() {
console.log('test2')
}
EventBus.on('test', test1)
EventBus.on('test', test2)
// EventBus.off('test', test1)
// EventBus.off('test', test2)
setTimeout(() => {
EventBus.emit('test', 111)
}, 1000)
很nice, 没有发现bug,那就到这了,简单实现了一个事件总线功能。