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 相关文章推荐
Z-Blog中用到的js代码
Mar 15 Javascript
javascript fullscreen全屏实现代码
Apr 09 Javascript
js textarea自动增高并隐藏滚动条
Dec 16 Javascript
jquery scroll()区分横向纵向滚动条的方法
Apr 04 Javascript
js使用心得分享
Jan 13 Javascript
JavaScript实现图片滑动切换的代码示例分享
Mar 06 Javascript
JavaScript面试开发常用的知识点总结
Aug 08 Javascript
微信小程序 教程之注册程序
Oct 17 Javascript
基于js 本地存储(详解)
Aug 16 Javascript
基于node.js express mvc轻量级框架实践
Sep 14 Javascript
Vue CLI3 如何支持less的方法示例
Aug 29 Javascript
使用post方法实现json往返传输数据的方法
Mar 30 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
php 读取文件乱码问题
2010/02/20 PHP
php查看当前Session的ID实例
2015/03/16 PHP
PHP对象实例化单例方法
2017/01/19 PHP
PHP四种排序算法实现及效率分析【冒泡排序,插入排序,选择排序和快速排序】
2018/04/27 PHP
js获取指定日期周数以及星期几的小例子
2014/06/27 Javascript
JS模拟酷狗音乐播放器收缩折叠关闭效果代码
2015/10/29 Javascript
JavaScript中关于for循环删除数组元素内容时出现的问题
2016/11/21 Javascript
浅谈javascript中的数据类型转换
2016/12/27 Javascript
angularjs实现的前端分页控件示例
2017/02/10 Javascript
js 实现获取name 相同的页面元素并循环遍历的方法
2017/02/14 Javascript
Bootstrap 表单验证formValidation 实现远程验证功能
2017/05/17 Javascript
vue中路由参数传递可能会遇到的坑
2017/12/07 Javascript
微信小程序实现左右列表联动
2020/05/19 Javascript
JS中的函数与对象的创建方式
2019/05/12 Javascript
js微信分享接口调用详解
2019/07/23 Javascript
js实现简单的打印表格
2020/01/15 Javascript
[07:43]《辉夜杯》公开赛晋级外卡赛战队—TRG训练生活探秘
2015/12/11 DOTA
[44:51]2018DOTA2亚洲邀请赛 4.4 淘汰赛 VP vs Liquid 第二场
2018/04/05 DOTA
TensorFlow实现非线性支持向量机的实现方法
2018/04/28 Python
Python实现全排列的打印
2018/08/18 Python
python存储16bit和32bit图像的实例
2018/12/05 Python
Python Tkinter 简单登录界面的实现
2019/06/14 Python
Python字典推导式将cookie字符串转化为字典解析
2019/08/10 Python
python实现简单银行管理系统
2019/10/25 Python
免税水晶:Duty Free Crystal
2019/05/13 全球购物
Python面试题:Python里面如何生成随机数
2015/03/12 面试题
招商经理岗位职责
2013/11/16 职场文书
材料物理专业个人求职信
2013/12/15 职场文书
《金孔雀轻轻跳》教学反思
2014/04/20 职场文书
助人为乐道德模范事迹材料
2014/08/16 职场文书
员工团队活动方案
2014/08/28 职场文书
指导教师推荐意见
2015/06/05 职场文书
中秋节感想
2015/08/10 职场文书
Golang 如何实现函数的任意类型传参
2021/04/29 Golang
Anaconda配置各版本Pytorch的实现
2021/08/07 Python
Win11快速关闭所有广告推荐
2022/04/19 数码科技