JS自定义事件

自定义事件,就是自己定义事件类型,自己定义事件处理函数。

我们平时操作dom时经常会用到onclick、onmousemove等浏览器特定行为的事件类型。

封装is自定义事件基本的构思:

var eventTarget = {
  addEvent: function(){
    //添加事件
  },
  fireEvent: function(){
    //触发事件
  },
  removeEvent: function(){
    //移除事件
  }
};

在js默认事件中事件类型以及对应的执行函数是一一对应的,但是自定义事件,需要一个映射表来建立两者之间的联系。

如:  这样每个类型可以处理多个事件函数

handlers = {
      "type1":[
            "fun1",
            "fun2",
            // "..."
         ],
       "type2":[
            "fun1",
            "fun2"
             // "..."
         ]
         //"..."
}

代码实现:

function EventTarget(){
    //事件处理程序数组集合
    this.handlers={};
}

//自定义事件的原型对象
EventTarget.prototype={
    //设置原型构造函数链
    constructor:EventTarget,
    //注册给定类型的事件处理程序
    //type->自定义事件类型,如click,handler->自定义事件回调函数
    addEvent:function(type,handler){
        //判断事件处理函数中是否有该类型事件
        if(this.handlers[type]==undefined){
            this.handlers[type]=[];
        }
        this.handlers[type].push(handler);
    },

    //触发事件
    //event为一个js对象,属性中至少包含type属性。
    fireEvent:function(event){
        //模拟真实事件的event
        if(!event.target){
            event.target=this;
        }
        //判断是否存在该事件类型
        if(this.handlers[event.type] instanceof Array){
            var items=this.handlers[event.type];
            //在同一事件类型下可能存在多个事件处理函数,依次触发
            //执行触发
            items.forEach(function(item){
                item(event);
            })
        }
    },

    //删除事件
    removeEvent:function(type,handler){
        //判断是否存在该事件类型
        if(this.handlers[type] instanceof Array){
            var items=this.handlers[type];
            //在同一事件类型下可能存在多个处理事件
            for(var i=0;i<items.length;i++){
                if(items[i]==handler){
                    //从该类型的事件数组中删除该事件
                    items.splice(i,1);
                    break;
                }
            }    
        }
    }    
}
            
//调用方法
function fun(){
    console.log('执行该方法');
}
function fun1(obj){
    console.log('run '+obj.min+'s');
}
var target=new EventTarget();
target.addEvent("run",fun);//添加事件
target.addEvent("run",fun1);//添加事件

target.fireEvent({type:"run",min:"30"});//执行该方法   123

target.removeEvent("run",fun);//移除事件

target.fireEvent({type:"run",min:"20"});//123

为什么要把方法添加到对象原型上?

在构造函数中加属性,在原型中加方法。

将属性和方法都写在构造函数里是没有问题的,但是每次进行实例化的过程中,要重复创建功能不变的方法。

由于方法本质上是函数,其实也就是在堆内存中又新建了一个对象空间存放存储函数,造成了不必要的资源浪费。

在本身添加会导致每次对象实例化时代码被复制,都需要申请一块内存存放该方法。

写一个EventEmitter类,包括on()、off()、once()、emit()方法

once():为指定事件注册一个单次监听器,单次监听器最多只触发一次,触发后立即解除监听器。

class EventEmitter{
            constructor(){
                this.handlers={};
            }
            on(type,fn){
                if(!this.handlers[type]){
                    this.handlers[type]=[];
                }
                this.handlers[type].push(fn);
                return this;
            }
            off(type,fn){
                let fns=this.handlers[type];
                for(let i=0;i<fns.length;i++){
                    if(fns[i]==fn){
                        fns.splice(i,1);
                        break;
                    }
                }
                return this;
            }
            emit(...args){
                let type=args[0];
                let params=[].slice.call(args,1);
                let fn=this.handlers[type];
                fn.forEach((item)=>{
                    item.apply(this,params);//执行函数
                })
                return this;
            }
            once(type,fn){
                let wrap=(...args)=>{
                    fn.apply(this,args);//执行事件后删除
                    this.off(type,wrap);
                }
                this.on(type,wrap);//再添加上去
                return this;
            }
        }
        
        let emitter=new EventEmitter();
        function fun1(){
            console.log('fun1');
        }
        function fun2(){
            console.log('fun2');
        }
        function fun3(){
            console.log('fun3');
        }
        emitter.on('TEST1',fun1).on('TEST2',fun2).emit('TEST1').once('TEST2',fun3);
        emitter.emit("TEST2");
原文地址:https://www.cnblogs.com/xiaoan0705/p/10574223.html