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


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

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

    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]
    		}
    	}
    

    $emit

     

     //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); }

    $off

    /*移除自定义事件监听器。
    	如果没有提供参数,则移除所有的事件监听器;
    	如果只提供了事件,则移除该事件所有的监听器;
    	如果同时提供了事件与回调,则只移除这个回调的监听器。
    	*/
    	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函数添加了属性方便找到它

     

     

  • 相关阅读:
    Maven 查看jar包的间接依赖
    Maven 下载一个 jar 包 及其它所有依赖的jar 到本地
    maven 自动构建 web 工程模板命令
    Linux Centos系统中设置定时重启
    (转)关于Android中为什么主线程不会因为Looper.loop()里的死循环卡死?引发的思考,事实可能不是一个 epoll 那么 简单。
    Linux中设置系统时间和时区
    版本管理工具svn(转)
    #pragma预处理命令
    插入排序
    选择排序
  • 原文地址:https://www.cnblogs.com/hjj2ldq/p/9570070.html
Copyright © 2020-2023  润新知