什么是EventEmitter?EventEmitter类似于Vue中的事件总线。有on、off、emit、once方法。接下来以Vue事件总线的方式进行解释,方便理解
首先,我们使用Class搭建起这个函数(普通函数也可以)
class EventEmitter {
constructor() {
// 初始化一个事件中心
this.emitter = {
};
// 事件中心保存的内容是下面这样的,因为可以同时监听多次相同的事件
// this.emitter = {
// 'eventName1': [callback1, callback2, ...],
// 'eventName2': [callback1, callback2, ...],
// };
}
}
首先实现on
函数。on
函数接收2个参数,第一个参数是事件名称,第二个参数的执行的回调函数。当我们使用emit派发事件时,on
函数监听到就会执行相应的回调函数。
on(name, callback) {
// 获取事件中心所存储的对应名称的事件
const callbacks = this.emitter[name];
// 如果保存过内容,就接着往里面添加,否则就当前callback就是第一个
if (callbacks) {
this.emitter[name].push(callback);
} else {
this.emitter[name] = [callback];
}
}
监听的on
函数有了,接下来实现派发事件的emit
函数。emit
函数接收2个参数,第一个参数是事件名称,第二个参数是要传递的参数。
emit(name, ...args) {
// 获取事件中心所存储的对应名称的事件
const callbacks = this.emitter[name];
// 如果存在事件,就循环将监听的事件都触发,并且将参数传递过去
if (callbacks) {
callbacks.forEach(callback => {
callback.apply(this, args);
});
}
}
如果觉得监听的事件过多想要删除掉怎么办,off
函数出现了。off
函数接收2个参数,第一个参数是事件名称,第二参数是要卸载的函数
off(name, fn) {
// 获取事件中心所存储的对应名称的事件
const callbacks = this.emitter[name];
// 存在回调
if (callbacks) {
// 找到当前要卸载的函数
const index = callbacks.findIndex(item => item === fn);
// 从事件列表中删除
this.emitter[name].splice(index, 1);
}
}
最后是只触发一次的once
。once
函数接收2个参数,第一个参数是事件名称,第二个参数的执行的回调。
once(name, callback) {
// 2、在绑定事件中执行并卸载,到达只执行一次的效果
const fn = (...args) {
fn.apply(this, args);
this.off(name, fn);
}
// 1、绑定事件
this.on(name, fn);
}
完整代码:
class EventEmitter {
constructor() {
this.emitter = {
};
}
on(name, callback) {
const callbacks = this.emitter[name];
if (callbacks) {
this.emitter[name].push(callback);
} else {
this.emitter[name] = [callback];
}
}
emit(name, ...args) {
const callbacks = this.emitter[name];
if (callbacks) {
callbacks.forEach(callback => {
callback.apply(this, args);
});
}
}
off(name, fn) {
const callbacks = this.emitter[name];
if (callbacks) {
const index = callbacks.findIndex(item => item === fn);
this.emitter[name].splice(index, 1);
}
}
once(name, callback) {
const fn = (...args) => {
fn.apply(this, args);
this.off(name, fn);
}
this.on(name, fn);
}
}
测试:
const e = new Emitter();
// on
e.on('a', (...args) => {
// fn1
console.log('a', ...args);
});
e.on('a', (...args) => {
// fn2
console.log('a', ...args);
});
e.on('b', (..args) => {
// fn3
console.log('b', ...args);
});
// 此时emitter中保存的是 this.emitter = { a: [fn1, fn2], b: [fn3] }
// emit
e.emit('a', 'a1', 'a2', 'a3', 'a4'); // 输出2次 a1、a2、a3、a4
e.emit('b', 'b'); // 输出一次 b
// off
const fn = () => {
console.log('off fn');
};
e.on('b', fn);
e.emit('b'); // 触发输出2次内容,分别为b和off fn
e.off('b', fn); // 卸载
e.emit('b'); // 再次触发,只输出b
// once
e.once('c', () => {
console.log(e.emitter); // this.emitter = { c: [fn] }
console.log('once');
});
e.emit('c', () => {
console.log(e.emitter); // this.emitter = { c: [] }
});