zoukankan      html  css  js  c++  java
  • 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");
  • 相关阅读:
    数学之路-python计算实战(1)-ubuntu安装pypy
    myeclipse中Servlet出错
    从IBM的计划中分析出中国重新相当然的错误选择吗
    辛星浅谈mysql中的数据碎片以及引擎为MyISAM下的操作
    微信前端js sdk以外的开发
    Hadoop生态系统学习路线
    还原对于server失败 备份集中的数据库备份与现有数据库不同
    hdu 4549 M斐波那契数列(矩阵高速幂,高速幂降幂)
    POJ 题目3667 Hotel(线段树,区间更新查询,求连续区间)
    阿里上市:盘点马云这些年
  • 原文地址:https://www.cnblogs.com/xiaoan0705/p/10574223.html
Copyright © 2011-2022 走看看