vue中的$on,$emit,$once,$off源码实现

这几种模式是基于订阅观察者模式的,维护一个事件中心,on的时候将事件按名称存在事件中内心,称之为订阅者,而后emit将对应的事件进行发布,去执行事件中内心的对应的监听器。javascript

第一步就是建立一个构造构造,维护一个事件中心eventsjava

function EventEmiter(){ this.events = {} } 

$on数组

 //event能够是事件名数组 EventEmiter.prototype.on = function(event,cb){ //多个事件 if(event instanceof Array){ event.forEach(fn=>this.on(fn,cb)) } //单个事件 if(this.events[event]){ this.events[event].push(cb) }else{ this.events[event] = [cb] } } 

$emitapp

 

 //cb 参数:单个事件名,args参数 this.emit('evt',a,b,c) EventEmiter.prototype.emit = function(event){ let args = Array.from(arguments).slice(1) let cbs = this.events[event]; if(cbs){ cbs.forEach(cb=>cb.apply(this,args)) } } 

$once函数

// 事件回调执行一次就清除事件,参数:单个事件名,单个监听器 EventEmiter.prototype.once = function(event,cb){ function oneTime(){
              //先执行回调,而后清除该事件的对应回调 cb.apply(this,arguments) this.off(event,cb) }
//on函数的fn属性添加一个标记,cb,方便循环off清除(提供了事件与回调的时候) oneTime.cbName = cb; this.on(event,oneTime); }

$offthis

/*移除自定义事件监听器。 若是没有提供参数,则移除全部的事件监听器; 若是只提供了事件,则移除该事件全部的监听器; 若是同时提供了事件与回调,则只移除这个回调的监听器。 */ EventEmiter.prototype.off = function(event,cb){ if(!arguments){ this.events = Object.create(null) } if(event instanceof Array){ event.forEach(evt=>this.off(evt,cb)) } if(!cb){ this.events[event] = null } if(cb){ let cbs = this.events[event] if(cbs){ for(let i = 0;i<cbs.length;i++){ if(cb === cbs[i] || cb === cbs[i].cbName){ cbs.splice(i,1) break } } } } } 

总结:其实原理很是简单,要注意的是$once 不是直接$on提交对应的回调函数,而是包装成另外的On函数,On函数做为回调Push进事件中心。On函数自己的做用是执行一次事件的回调,而后就立马$off去出该事件的监听回调。同时,On函数已经不是原来的cb回调了,因此为了待会$off的时候能准确找到背后的那个cb,因此给On函数添加了属性方便找到它spa

相关文章
相关标签/搜索