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

Posted fs0196

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue中的$on,$emit,$once,$off源码实现相关的知识,希望对你有一定的参考价值。

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

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

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

  1.  
    function EventEmiter(){
  2.  
    this.events = {}
  3.  
    }
  4.  
     

$on

技术图片

  1.  
    //event可以是事件名数组
  2.  
    EventEmiter.prototype.on = function(event,cb){
  3.  
    //多个事件
  4.  
    if(event instanceof Array){
  5.  
    event.forEach(fn=>this.on(fn,cb))
  6.  
    }
  7.  
    //单个事件
  8.  
    if(this.events[event]){
  9.  
    this.events[event].push(cb)
  10.  
    }else{
  11.  
    this.events[event] = [cb]
  12.  
    }
  13.  
    }
  14.  
     

$emit

技术图片

 

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

$once

技术图片

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

$off

技术图片

  1.  
    /*移除自定义事件监听器。
  2.  
    如果没有提供参数,则移除所有的事件监听器;
  3.  
    如果只提供了事件,则移除该事件所有的监听器;
  4.  
    如果同时提供了事件与回调,则只移除这个回调的监听器。
  5.  
    */
  6.  
    EventEmiter.prototype.off = function(event,cb){
  7.  
    if(!arguments){
  8.  
    this.events = Object.create(null)
  9.  
    }
  10.  
    if(event instanceof Array){
  11.  
    event.forEach(evt=>this.off(evt,cb))
  12.  
    }
  13.  
    if(!cb){
  14.  
    this.events[event] = null
  15.  
    }
  16.  
    if(cb){
  17.  
    let cbs = this.events[event]
  18.  
    if(cbs){
  19.  
    for(let i = 0;i<cbs.length;i++){
  20.  
    if(cb === cbs[i] || cb === cbs[i].cbName){
  21.  
    cbs.splice(i,1)
  22.  
    break
  23.  
    }
  24.  
    }
  25.  
    }
  26.  
    }
  27.  
    }
  28.  
     

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

 

以上是关于vue中的$on,$emit,$once,$off源码实现的主要内容,如果未能解决你的问题,请参考以下文章

Vue 事件相关实例方法---on/emit/off/once

vue中$refs, $emit, $on, $once, $off的使用详解

Vue中事件总线$bus的用法及$on$off和$emit的使用

Vue中事件总线$bus的用法及$on$off和$emit的使用

Vue事件总线(EventBus)$on$emit$off

$on在构造器外部添加事件$once执行一次的事件$off关闭事件