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 相关文章推荐
JQuery从头学起第一讲
Jul 04 Javascript
cookie中的path与domain属性详解
Dec 18 Javascript
浅谈Javascript 执行顺序
Dec 18 Javascript
js去除输入框中所有的空格和禁止输入空格的方法
Jun 09 Javascript
Jquery响应回车键直接提交表单操作代码
Jul 25 Javascript
Bootstrap Fileinput文件上传组件用法详解
May 10 Javascript
javascript设计模式之单体模式学习笔记
Feb 15 Javascript
尝试自己动手用react来写一个分页组件(小结)
Feb 09 Javascript
JavaScript数组去重的几种方法
Apr 07 Javascript
AngularJS实现的鼠标拖动画矩形框示例【可兼容IE8】
May 17 Javascript
微信小程序 bindtap 传参的实例代码
Feb 21 Javascript
js实现移动端图片滑块验证功能
Sep 29 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
ThinkPHP模版引擎之变量输出详解
2014/12/05 PHP
PHP中的随机性 你觉得自己幸运吗?
2016/01/22 PHP
Laravel获取所有的数据库表及结构的方法
2019/10/10 PHP
javascript 面向对象全新理练之继承与多态
2009/12/03 Javascript
jQuery的Ajax时无响应数据的解决方法
2010/05/25 Javascript
Jquery截取中文字符串的实现代码
2010/12/22 Javascript
JavaScript中几种排序算法的简单实现
2015/07/29 Javascript
微信小程序 navigation API实例详解
2016/10/02 Javascript
js利用clipboardData实现截屏粘贴功能
2016/10/12 Javascript
ReactJs设置css样式的方法
2017/06/08 Javascript
ionic3 懒加载
2017/08/16 Javascript
bootstrap Table服务端处理分页(后台是.net)
2017/10/19 Javascript
phantomjs导出html到pdf的方法总结
2017/10/19 Javascript
使用RxJS更优雅地进行定时请求详析
2019/06/02 Javascript
微信小程序从注册账号到上架(图文详解)
2019/07/17 Javascript
小程序简单两栏瀑布流效果的实现
2019/12/18 Javascript
Vue路由的模块自动化与统一加载实现
2020/06/05 Javascript
微信小程序动态评分展示/五角星展示/半颗星展示/自定义长度展示功能的实现
2020/07/22 Javascript
Vue3+elementui plus创建项目的方法
2020/12/01 Vue.js
[03:31]DOTA2英雄基础教程 大地之灵
2013/12/17 DOTA
Django中对数据查询结果进行排序的方法
2015/07/17 Python
Python中使用OpenCV库来进行简单的气象学遥感影像计算
2016/02/19 Python
Python利用ORM控制MongoDB(MongoEngine)的步骤全纪录
2018/09/13 Python
详解Django-auth-ldap 配置方法
2018/12/10 Python
对python3 Serial 串口助手的接收读取数据方法详解
2019/06/12 Python
选择Python写网络爬虫的优势和理由
2019/07/07 Python
python GUI库图形界面开发之PyQt5表格控件QTableView详细使用方法与实例
2020/03/01 Python
python实现mask矩阵示例(根据列表所给元素)
2020/07/30 Python
利用Python pandas对Excel进行合并的方法示例
2020/11/04 Python
html5 input输入实时检测以及延时优化
2018/07/18 HTML / CSS
大学生职业生涯规划书范文
2014/01/04 职场文书
美术专业个人自我评价
2014/01/18 职场文书
旅游市场营销方案
2014/03/09 职场文书
学校感恩节活动策划方案
2014/10/06 职场文书
捐款通知怎么写
2015/04/24 职场文书
初中班长竞选稿
2015/11/20 职场文书