JavaScript绑定事件监听函数的通用方法


Posted in Javascript onMay 14, 2016

事件绑定的3中常用方法:传统绑定、W3C绑定方法、IE绑定方法。但是,在实际开发中对于我们来讲重要的是需要一个通用的、跨浏览器的绑定方法。如果我们在互联网上搜索一下会发现许多方法,以下是比较知名的几种方法:

在开始学期下面几种方法之前,应当讨论一下,一个好的addEvent()方法应当达到哪些要求:

a、支持同一元素的同一事件句柄可以绑定多个监听函数;

b、如果在同一元素的同一事件句柄上多次注册同一函数,那么第一次注册后的所有注册都被忽略;

c、函数体内的this指向的应当是正在处理事件的节点(如当前正在运行事件句柄的节点);

d、监听函数的执行顺序应当是按照绑定的顺序执行;

e、在函数体内不用使用 event = event || window.event; 来标准化Event对象;

一、John Resig 所写的 addEvent() 函数

function addEvent( obj, type, fn ) {
  if ( obj.attachEvent ) {
   obj['e'+type+fn] = fn;
   obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
   obj.attachEvent( 'on'+type, obj[type+fn] );
  } else
   obj.addEventListener( type, fn, false );
 }
 function removeEvent( obj, type, fn ) {
  if ( obj.detachEvent ) {
   obj.detachEvent( 'on'+type, obj[type+fn] );
   obj[type+fn] = null;
  } else
   obj.removeEventListener( type, fn, false );
 }

这个函数如此简单易懂,的确非常令人惊讶。那么我们还是要看看上面的五点要求:

对于第一点满足了;

对于第三点和第五点,肯定也满足了;

对于第二点,并没有满足,因为addEventListener()会忽略重复注册,而attachEvent()则不会忽略;

但是第四点,并没有满足,因为Dom标准没有确定调用一个对象的时间处理函数的顺序,所以不应该想当然的认为它们以注册的顺序调用。

但是这个函数仍然是一个非常优秀的函数。

二、Dean Edward 所写的 addEvent() 函数

function addEvent(element, type, handler) {
 if (!handler.$$guid) handler.$$guid = addEvent.guid++;
 if (!element.events) element.events = {};
  var handlers = element.events[type];
 if (!handlers) {
  handlers = element.events[type] = {};
  if (element["on" + type]) {
   handlers[0] = element["on" + type];
  }
 }
 handlers[handler.$$guid] = handler;
 element["on" + type] = handleEvent;
}

addEvent.guid = 1;
 
function removeEvent(element, type, handler) {
 if (element.events && element.events[type]) {
  delete element.events[type][handler.$$guid];
 }
}
function handleEvent(event) {
 var returnValue = true;
 event = event || fixEvent(window.event);
 var handlers = this.events[event.type];
 for (var i in handlers) {
  this.$$handleEvent = handlers[i];
  if (this.$$handleEvent(event) === false) {
   returnValue = false;
  }
 }
 return returnValue;
};
 
function fixEvent(event) {
 event.preventDefault = fixEvent.preventDefault;
 event.stopPropagation = fixEvent.stopPropagation;
 return event;
};
fixEvent.preventDefault = function() {
 this.returnValue = false;
};
fixEvent.stopPropagation = function() {
 this.cancelBubble = true;
};

该函数使用了传统的绑定方法,所以它可以在所有的浏览器中工作,也不会造成内存泄露。

但是对于最初提出的5点,该函数只是满足了前四点。只有最后一点没有满足,因为在JavaScript中对for/in语句的执行顺序没有规定是按照赋值的顺序执行,尽管大部分时刻是按照预期的顺序执行,因此在不同的JavaScript版本或实现中这一语句的顺序有可能不同。

三、Dean Edward 的 addEvent() 函数的改进

Array.prototype.indexOf = function( obj ){
 var result = -1 , length = this.length , i=length - 1;
 for ( ; i>=0 ; i-- ) {
  if ( this[i] == obj ) {
   result = i;
   break;
  }
 }
 return result;
}
Array.prototype.contains = function( obj ) {
 return ( this.indexOf( obj ) >=0 )
}
Array.prototype.append = function( obj , nodup ) {
 if ( !(nodup && this.contains( obj )) ) {
  this[this.length] = obj;
 }
}
Array.prototype.remove = function( obj ) {
 var index = this.indexOf( obj );
 if ( !index ) return ;
 return this.splice( index , 1);
};
function addEvent(element , type , fun){
 if (!element.events) element.events = {};   
 var handlers = element.events[type];
 if (!handlers) {
  handlers = element.events[type] = [];
  if(element['on' + type]) {  
   handlers[0] = element['on' + type];
  }
 }
 handlers.append( fun , true)
 element['on' + type] = handleEvent;
}
function removeEvent(element , type , fun) {
 if (element.events && element.events[type]) {
  element.events[type].remove(fun); 
 }
}
function handleEvent(event) {
 var returnValue = true , i=0;
 event = event || fixEvent(window.event);
 var handlers = this.events[event.type] , length = handlers.length;
 for ( ; i < length ; i++) {
  if ( handlers[i].call( this , event) === false ){
   returnValue = false;
  }
 }
 return returnValue;
}
function fixEvent(event) {
 event.preventDefault = fixEvent.preventDefault;
 event.stopPropagation = fixEvent.stopPropagation;
 return event;
}
fixEvent.preventDefault = function() {
 this.returnValue = false;
};
fixEvent.stopPropagation = function() {
 this.cancelBubble = true;
};

该函数是本人对Dean Edward 的 addEvent() 函数的改进,完全满足了最初提出的5点要求,希望对大家的学习有所帮助,谢谢大家的阅读。

Javascript 相关文章推荐
json简单介绍
Jun 10 Javascript
javascript 特殊字符串
Feb 25 Javascript
javascript css styleFloat和cssFloat
Mar 15 Javascript
基于Jquery+Ajax+Json的高效分页实现代码
Oct 29 Javascript
javascript实现焦点滚动图效果 具体方法
Jun 24 Javascript
jquery中ready()函数执行的时机和window的load事件比较
Jun 22 Javascript
jQuery实现的省市县三级联动菜单效果完整实例
Aug 01 Javascript
浅谈jquery高级方法描述与应用
Oct 04 Javascript
Vue.js组件实现选项卡以及切换特效
Jul 24 Javascript
layui操作列按钮个数和文字颜色的判断实例
Sep 11 Javascript
详解Vue3中对VDOM的改进
Apr 23 Javascript
Vue Render函数创建DOM节点代码实例
Jul 08 Javascript
易被忽视的js事件问题总结
May 14 #Javascript
jQuery防止重复绑定事件的解决方法
May 14 #Javascript
jQuery基于扩展简单实现倒计时功能的方法
May 14 #Javascript
jquery动态切换背景图片的简单实现方法
May 14 #Javascript
jQuery基于$.ajax设置移动端click超时处理方法
May 14 #Javascript
jQuery基于扩展实现的倒计时效果
May 14 #Javascript
Angularjs中UI Router的使用方法
May 14 #Javascript
You might like
?生?D片??C字串
2006/12/06 PHP
php实现高效获取图片尺寸的方法
2014/12/12 PHP
php实现从上传文件创建缩略图的方法
2015/04/02 PHP
PHP生成json和xml类型接口数据格式
2015/05/17 PHP
为radio类型的INPUT添加客户端脚本(附加实现JS来禁用onClick事件思路代码)
2010/11/11 Javascript
JQuery中对服务器控件 DropdownList, RadioButtonList, CheckboxList的操作总结
2011/06/28 Javascript
js控制滚动条缓慢滚动到顶部实现代码
2013/03/20 Javascript
jquery实现图片上传前本地预览
2017/04/28 jQuery
详解vue express启动数据服务
2017/07/05 Javascript
js面向对象之实现淘宝放大镜
2020/01/15 Javascript
详解JavaScript中的Object.is()与&quot;===&quot;运算符总结
2020/06/17 Javascript
Vue在H5 项目中使用融云进行实时个人单聊通讯
2020/12/14 Vue.js
[36:41]完美世界DOTA2联赛循环赛FTD vs Magma第一场 10月30日
2020/10/31 DOTA
Flask入门教程实例:搭建一个静态博客
2015/03/27 Python
Django配置celery(非djcelery)执行异步任务和定时任务
2018/07/16 Python
python 通过 socket 发送文件的实例代码
2018/08/14 Python
python列表每个元素同增同减和列表元素去空格的实例
2019/07/20 Python
Python连接字符串过程详解
2020/01/06 Python
Python如何操作office实现自动化及win32com.client的运用
2020/04/01 Python
学会python自动收发邮件 代替你问候女友
2020/05/20 Python
python 常见的反爬虫策略
2020/09/27 Python
iRobot官网:改变生活的家用机器人品牌
2016/09/20 全球购物
美国指甲油品牌:Deco Miami
2017/01/30 全球购物
标签和贴纸印刷:Lightning Labels
2018/03/22 全球购物
英国美术用品购物网站:Cass Art
2019/10/08 全球购物
电影T恤、80年代T恤和80年代服装:TV Store Online
2020/01/05 全球购物
采用怎样的方法保证数据的完整性
2013/12/02 面试题
银行个人求职自荐信范文
2013/12/16 职场文书
幼儿园家长评语大全
2014/04/16 职场文书
搞笑爱情保证书
2014/04/29 职场文书
法律专业求职信
2014/05/24 职场文书
2014党支部对照检查材料思想汇报
2014/10/05 职场文书
网站出售协议书范文
2014/10/10 职场文书
go语言中json数据的读取和写出操作
2021/04/28 Golang
Nginx反向代理至go-fastdfs案例讲解
2021/08/02 Servers
Springboot中如何自动转JSON输出
2022/06/16 Java/Android