小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
Event bus 应该拥有的几个方法
on:注册事件,一般需要提供两个参数,一个是事件名,一个是回调函数
emit:触发事件,一般需要支持多个参数,第一个是事件名,后面为传递给回调函数的参数
off:注销事件,一般需要提供两个参数,一个是事件名,一个是回调函数
once:注册一个只会执行一次的事件,一般需要提供两个参数,一个是事件名,一个是回调函数
一步一步实现
创建一个类
使用 es6 语法,并定一个存放所有事件的对象
class EventEmitter {
constructor() {
// 存放所有的事件
this.events = {};
}
}
实现 on 方法
on 方法应该接受两个参数,event, cb;并且同一个事件,可以注册多个回调函数,所以 this.events[event] 应该是一个 Array 类型
on(event, cb) {
// 第一次注册事件,先初始化 this.events[event]
if(!this.events[event]) {
this.events[event] = [];
}
// 将回调函数放入数组中
this.events[event].push(cb);
}
实现 emit 方法
emit 方法应该接受多个参数,event, ...args;
emit(event, ...args) {
const cbs = this.events[event];
// emit之前,应该先调用on函数注册
if(!cbs) {
console.warn(`${event} is not registed`);
return this;
}
// 遍历回调函数数组,依次调用
cbs.forEach(cb => cb.apply(this, args));
// 返回this 可以 a.emit().emit() 链式调用
return this;
}
实现 off 方法
emit 方法应该接受两个参数,event, cb;如果第二个参数不传,则认为注销该事件的所有回调函数
off(event, cb) {
// 如果第二个参数不传,则认为注销该事件的所有回调函数
if(!cb) {
this.events[event] = null;
} else {
// 过滤掉传进来的 cb
this.events[event] = this.events[event].filter(item => item !== cb);
}
return this;
}
实现 once 方法
once 方法应该接受两个参数,event, cb;并且该 cb 回调函数在完成一次触发后,应该被注销
once(event, cb) {
// 封装一个方法,利用off函数,注销cb
const func = (...args) => {
this.off(event, func);
cb.apply(this, args);
}
// 调用on函数注册
this.on(event, func);
}
完整版代码
class EventEmitter {
constructor() {
this.events = {};
}
on(event, cb) {
if(!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(cb);
}
emit(event, ...args) {
const cbs = this.events[event];
if(!cbs) {
console.warn(`${event} is not registed`);
return this;
}
cbs.forEach(cb => cb.apply(this, args));
return this;
}
once(event, cb) {
const func = (...args) => {
this.off(event, func);
cb.apply(this, args);
}
this.on(event, func);
}
off(event, cb) {
if(!cb) {
this.events[event] = null;
} else {
this.events[event] = this.events[event].filter(item => item !== cb);
}
return this;
}
}
测试结果
const ev = new EventEmitter();
const clickFucCall = (params) => {
console.log(`click event params is ${params}`);
}
ev.on('click', clickFucCall)
ev.once('clickOnce', (params) => {
console.log(`clickOnce event params is ${params}`);
})
ev.emit('click', '第一次click触发');
ev.emit('click', '第二次click触发');
ev.off('click', clickFucCall);
ev.emit('click', '第三次click触发');
ev.emit('clickOnce', '第一次clickOnce触发');
ev.emit('clickOnce', '第二次clickOnce触发');
// 输出
// click event params is 第一次click触发
// click event params is 第二次click触发
// clickOnce event params is 第一次clickOnce触发