vue事件机制
vue官方Api上提供了四个事件,$on, $once, $off, $emit, 这几个事件都是基于订阅观察者模式实现的,在vm上创建一个event对象存放时间,on方法将事件添加到事件中心,emit将对应的事件发布,off移除对应事件,once监听自定义时间,但只触发一次。
实现原理
实现一个简易的方法,拥有以上几个事件。
class Vm {
_events = {} // 定义一个空的事件
on(event, fn) { // event: string | array
if(Array.isArray(event)) { //多个事件
event.forEach(item => this.on(item, fn))
}else {
(this._events[event] || (this._events[event] = [])).push(fn); //将事件推送进事件中心(||优先级比=高)
}
}
emit(event) {
const fns = this._events[event];
const args = Array.from(arguments).slice(1);
if(fns) {
fns.forEach(fn => fn.apply(this, args)) // 遍历执行
}
}
once(event, fn) {
function oneTime() {
this.off(event, oneTime); // 第一次执行时将该事件销毁
fn.apply(this, arguments) // 执行fn方法
}
this.on(event, oneTime);
}
off(event, fn) {
if(!arguments.length) { // 为指定事件名称,清空所有事件
this._events = Object.creact(null);
return;
}
if(Array.isArray(event)) { // 多个事件递归注销事件
event.forEach(evt => this.off(evt, fn))
}
const fns = this._events[event];
if(!fns) return; // 如果不存在该事件直接返回
if(!fn) { // 未指定事件的对应方法,则注销该事件下的所有方法
this._events[event] = null;
return;
}
const idx = fns.indexOf(fn);
if(idx > -1) {
fns.splice(i, 1);
}
// for(var i = 0; i < fns.length; i++) { // 遍历event下的方法
// if(fns[i] === fn) {
// fns.splice(i, 1);
// break;
// }
// }
}
}
on方法测试
let vm = new Vm();
vm.on(['a', 'b'], ()=>console.log(1));
vm.on('a', ()=>console.log(2));
emit方法测试
vm.emit('a'); //1,2
vm.emit('b'); // 1
off方法测试
vm.off('b')
once方法测试
vm.once('c', ()=>console.log('cccc'))
vm.emit('c'); //ccc