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 相关文章推荐
js 省地市级联选择
Feb 07 Javascript
新浪微博字数统计 textarea字数统计实现代码
Aug 28 Javascript
JS表格组件神器bootstrap table详解(强化版)
May 26 Javascript
聊一聊JS中this的指向问题
Jun 17 Javascript
js插件Jcrop自定义截取图片功能
Oct 14 Javascript
使用Bootstrap Tabs选项卡Ajax加载数据实现
Dec 23 Javascript
Node.js中看JavaScript的引用
Apr 22 Javascript
IScroll5实现下拉刷新上拉加载的功能实例
Aug 11 Javascript
不得不知的ES6小技巧
Jul 28 Javascript
微信小程序实现日期格式化和倒计时
Nov 01 Javascript
Vue SPA 初次进入加载动画实现代码
Nov 14 Javascript
JS实现秒杀倒计时特效
Jan 02 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
php5新改动之短标记启用方法
2008/09/11 PHP
用php实现的下载css文件中的图片的代码
2010/02/08 PHP
解析PayPal支付接口的PHP开发方式
2010/11/28 PHP
PHP的可变变量名的使用方法分享
2012/02/05 PHP
php打开文件fopen函数的使用说明
2013/07/05 PHP
php中__toString()方法用法示例
2016/12/07 PHP
PHP 根据key 给二维数组分组
2016/12/09 PHP
innerHTML与jquery里的html()区别介绍
2012/10/12 Javascript
JS删除数组元素的函数介绍
2013/03/27 Javascript
上传的js验证(图片/文件的扩展名)
2013/04/25 Javascript
Knockout visible绑定使用方法
2013/11/15 Javascript
jquery的总体架构分析及实现示例详解
2014/11/08 Javascript
JavaScript提高网站性能优化的建议(二)
2016/07/24 Javascript
原生js轮播(仿慕课网)
2017/02/15 Javascript
利用nodejs监控文件变化并使用sftp上传到服务器
2017/02/18 NodeJs
Kindeditor单独调用单图上传增加预览功能的实例
2017/07/31 Javascript
seajs实现强制刷新本地缓存的方法分析
2017/10/16 Javascript
React中的refs的使用教程
2018/02/13 Javascript
jQuery实现上下滚动公告栏详细代码
2018/11/21 jQuery
mock.js模拟前后台交互
2019/07/25 Javascript
python的pdb调试命令的命令整理及实例
2017/07/12 Python
PYTHON实现SIGN签名的过程解析
2019/10/28 Python
Python如何计算语句执行时间
2019/11/22 Python
如何将 awk 脚本移植到 Python
2019/12/09 Python
pycharm 实现本地写代码,服务器运行的操作
2020/06/08 Python
python写文件时覆盖原来的实例方法
2020/07/22 Python
python asyncio 协程库的使用
2021/01/21 Python
python+selenium实现12306模拟登录的步骤
2021/01/21 Python
美国婴儿用品及配件购买网站:Munchkin
2019/04/03 全球购物
留学自荐信的技巧
2013/10/17 职场文书
家长会邀请书
2014/01/25 职场文书
《中国的气候》教学反思
2014/02/23 职场文书
大四学生找工作的自荐信
2014/03/27 职场文书
基层党组织建设整改方案
2014/09/16 职场文书
2016年中秋祝酒词
2015/11/26 职场文书
CPU不支持Windows11系统怎么办
2021/11/21 数码科技