首页 > 编程 > JavaScript > 正文

详解javascript实现自定义事件

2019-11-20 10:45:47
字体:
来源:转载
供稿:网友

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

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

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

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

又或者

//DOM2级事件处理程序var oDiv = document.getElementById('oDiv');//非ieoDiv.addEventListener("click",function(){  alert("你点击了我");},false); //ieoDiv.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"});                   //123eventTarget.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

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

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

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表