• 详解javascript实现自定义事件


    这篇文章主要为大家介绍了javascript实现自定义事件的方法,自定义事件,顾名思义,就是自己定义事件类型,自己定义事件处理函数,javascript如何实现自定义事件,需要了解的朋友可以参考下

    我们平时在操作dom时候经常会用到onclick,onmouseover等一系列浏览器特定行为的事件, 
    那么自定义事件,顾名思义,就是自己定义事件类型,自己定义事件处理函数,在合适的时候需要哪个事件类型,就去调用哪个处理程序

    1.js所支持的浏览器默认事件

    浏览器特定行为的事件,或者叫系统事件,js默认事件等等都行,大家知道我指的什么就行,下文我叫他js默认事件。 
    js默认事件的事件绑定,事件移出等一系列操作,相信大家都有用到过,如:

    //DOM0级事件处理程序
    var oDiv = document.getElementById('oDiv');
    oDiv.onclick = function(){
      alert("你点击了我");
    }

    又或者

    //DOM2级事件处理程序
    var oDiv = document.getElementById('oDiv');
     
    //非ie
    oDiv.addEventListener("click",function(){
      alert("你点击了我");
    },false); 
     
    //ie
    oDiv.attachEvent("onclick", function(){
      alert("你点击了我");
    });

    所有我就不做过多的研究,毕竟我们来讨论js自定义事件,这里给出一个我之前封装过的处理js默认事件的代码:

    //跨浏览器的事件处理程序 
    //调用时候直接用domEvent.addEvent( , , );直接调用 
    //使用时候,先用addEvent添加事件,然后在handleFun里面直接写其他函数方法,如getEvent; 
    //addEventListener和attachEvent---都是dom2级事件处理程序 
    var domEvent = { 
      //element:dom对象,event:待处理的事件,handleFun:处理函数 
      //事件名称,不含“on”,比如“click”、“mouseover”、“keydown”等 
      addEvent:function(element,event,handleFun){ 
        //addEventListener----应用于mozilla 
        if(element.addEventListener){ 
          element.addEventListener(event,handleFun,false); 
        }//attachEvent----应用于IE 
        else if(element.attachEvent){ 
          element.attachEvent("on"+event,handleFun); 
        }//其他的选择dom0级事件处理程序 
        else{ 
          //element.onclick===element["on"+event]; 
          element["on"+event] = handleFun; 
        } 
      }, 
      //事件名称,含“on”,比如“onclick”、“onmouseover”、“onkeydown”等 
      removeEvent:function(element,event,handleFun){ 
        //removeEventListener----应用于mozilla 
        if (element.removeEventListener) { 
          element.removeEventListener(event,handleFun,false); 
        }//detachEvent----应用于IE 
        else if (element.detachEvent) { 
          element.detachEvent("on"+event,handleFun); 
        }//其他的选择dom0级事件处理程序 
        else { 
          element["on"+event] = null; 
        } 
      }, 
      //阻止事件冒泡 
      stopPropagation:function(event){ 
        if(event.stopPropagation){ 
          event.stopPropagation(); 
        }else{ 
          event.cancelBubble = true;//IE阻止事件冒泡,true代表阻止 
        } 
      }, 
      //阻止事件默认行为 
      preventDefault:function(event){ 
        if(event.preventDefault){ 
          event.preventDefault(); 
        }else{ 
          event.returnValue = false;//IE阻止事件冒泡,false代表阻止 
        } 
      }, 
      //获得事件元素 
      //event.target--非IE 
      //event.srcElement--IE 
      getElement:function(event){ 
        return event.target || event.srcElement; 
      }, 
      //获得事件 
      getEvent:function(event){ 
        return event? event : window.event; 
      }, 
      //获得事件类型 
      getType:function(event){ 
        return event.type; 
      } 
    }; 

    接下类我们不如正题,js自定义事件

    2.对象直接量封装js自定义事件

    根据上面的封装,我们可以这样构思

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

    相信这样大家还是比较好理解的,然后又有一个问题大家可以想到,那就是,js默认事件,js可以一一对应,知道那个是那个,那么我们的自定义事件呢,这个一一对应的映射表只能我们自己去建立,然后我这样

    var eventTarget = {
      //保存映射
      handlers:{},
      addEvent: function(){
        //处理代码
      },
      fireEvent: function(){
        //触发代码
      },
      removeEvent: function(){
        //移出代码
      }
    };

    我是这样构建这个映射关系的

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

    这样每一个类型可以有多个处理函数,以便于我们以后扩充 
    接下来就是代码方面的实战的,编写具体的处理代码了…

    相信大家对于这个思路已经很清楚了,我直接附上代码

    //直接量处理js自定义事件
    var eventTarget = {
      //保存事件类型,处理函数数组映射
      handlers:{},
      //注册给定类型的事件处理程序,
      //type -> 自定义事件类型, handler -> 自定义事件回调函数
      addEvent: function(type, handler){
        //判断事件处理数组是否有该类型事件
        if(eventTarget.handlers[type] == undefined){
          eventTarget.handlers[type] = [];
        }
        //将处理事件push到事件处理数组里面
        eventTarget.handlers[type].push(handler);
      },
      //触发一个事件
      //event -> 为一个js对象,属性中至少包含type属性,
      //因为类型是必须的,其次可以传一些处理函数需要的其他变量参数。(这也是为什么要传js对象的原因)
      fireEvent: function(event){
        //判断是否存在该事件类型
        if(eventTarget.handlers[event.type] instanceof Array){
          var _handler = eventTarget.handlers[event.type];
          //在同一个事件类型下的可能存在多种处理事件,找出本次需要处理的事件
          for(var i = 0; i < _handler.length; i++){
            //执行触发
            _handler[i](event);
          }
        }
      },
      //注销事件
      //type -> 自定义事件类型, handler -> 自定义事件回调函数
      removeEvent: function(type, handler){
        if(eventTarget.handlers[type] instanceof Array){
          var _handler = eventTarget.handlers[type];
          //在同一个事件类型下的可能存在多种处理事件,找出本次需要处理的事件
          for(var i = 0; i < _handler.length; i++){
            //找出本次需要处理的事件下标
            if(_handler[i] == handler){
              break;
            }
          }
          //删除处理事件
          _handler.splice(i, 1);
        }
      }
    };

    这是一种调用运行的方法

    eventTarget.addEvent("eat",function(){
      console.log(123);  //123
    });
    eventTarget.fireEvent({type: "eat"});

    这种方法有一个缺点,不能删除该处理事件,因为我们是用映射表做的,而且也不提倡,直接给映射表里面存这么多数据,有点多。

    另一种方法,将处理事件提取出来(推荐)

    function b(){
       console.log(123);
    }
    eventTarget.addEvent("eat",b);
    eventTarget.fireEvent({
      type: "eat"
    });                   //123
    eventTarget.removeEvent("eat",b);
    eventTarget.fireEvent({type: "eat"});  //

    也可以这样,传递更多的参数

    eventTarget.fireEvent({
      type: "eat",
      food: "banana"
    }); 
    function b(data){
       console.log(data.food); //banana
    }

    总结:字面量这种方法,有点儿缺点,就是万一一不小心,把某个属性在handler函数里面,赋值null,这样会造成我们的的eventTarget 方法崩盘。看来原型应该是个好方法,更安全一点。

    3.对象原型封装js自定义事件

    由于前面思路基本都讲清楚了,这里我直接附上代码,大家可以研究下其中的利弊,或许你可以找到更好的方法解决Ta…

    //自定义事件构造函数
    function EventTarget(){
      //事件处理程序数组集合
      this.handlers = {};
    }
    //自定义事件的原型对象
    EventTarget.prototype = {
      //设置原型构造函数链
      constructor: EventTarget,
      //注册给定类型的事件处理程序,
      //type -> 自定义事件类型, handler -> 自定义事件回调函数
      addEvent: function(type, handler){
        //判断事件处理数组是否有该类型事件
        if(typeof this.handlers[type] == 'undefined'){
          this.handlers[type] = [];
        }
        //将处理事件push到事件处理数组里面
        this.handlers[type].push(handler);
      },
      //触发一个事件
      //event -> 为一个js对象,属性中至少包含type属性,
      //因为类型是必须的,其次可以传一些处理函数需要的其他变量参数。(这也是为什么要传js对象的原因)
      fireEvent: function(event){
        //模拟真实事件的event
        if(!event.target){
          event.target = this;
        }
        //判断是否存在该事件类型
        if(this.handlers[event.type] instanceof Array){
          var handlers = this.handlers[event.type];
          //在同一个事件类型下的可能存在多种处理事件,找出本次需要处理的事件
          for(var i = 0; i < handlers.length; i++){
            //执行触发
            handlers[i](event);
          }
        }
      },
      //注销事件
      //type -> 自定义事件类型, handler -> 自定义事件回调函数
      removeEvent: function(type, handler){
        //判断是否存在该事件类型
        if(this.handlers[type] instanceof Array){
          var handlers = this.handlers[type];
          //在同一个事件类型下的可能存在多种处理事件
          for(var i = 0; i < handlers.length; i++){
            //找出本次需要处理的事件下标
            if(handlers[i] == handler){
              break;
            }
          }
          //从事件处理数组里面删除
          handlers.splice(i, 1);
        }
      }
    };

    调用方法

    function b(){
      console.log(123);
    }
     
    var target = new EventTarget();
    target.addEvent("eat", b);
     
    target.fireEvent({
      type: "eat"
    });                 //123

    原型这种方法,与直接量方法功能是一样的…

    以上就是本文的全部内容,希望对大家的学习有所帮助。

  • 相关阅读:
    在HTML中使用JavaScript
    小强的HTML5移动开发之路(49)——HTML5开发神器HBuilder
    小强的HTML5移动开发之路(48)——(小练习)新闻订阅系统【1】
    QT学习记录之控件布局
    QT学习记录之理解信号槽机制
    小强的HTML5移动开发之路(47)——jquery mobile基本的页面框架
    Linux下MySQL备份以及crontab定时备份
    Linux管理日记(三)
    小强的HTML5移动开发之路(46)——汇率计算器【2】
    kindeditor实现ctrl+v粘贴word图片并上传
  • 原文地址:https://www.cnblogs.com/jiangxiaobo/p/5829913.html
Copyright © 2020-2023  润新知