JavaScript作为一门基于事件驱动的语言(特别是用在DOM操作的时候),我们常常需要为DOM绑定各种各样的事件。然而,由于低版本的IE的不给力,在绑定事件和移除事件监听上都与众不同,我们常常需要自己封装一个跨浏览器绑定(移除)事件的函数。跨浏览器添加(移除)DOM事件的一种非常经典的实现代码如下:

//跨浏览器添加事件
function addHandler(target, eventType, handler) {
  if(target.addEventListener) { //DOM2 events
    target.addEventListener(eventType, handler, false);
  } else { //IE
    target.attachEvent("on" + eventType, handler);
  }
} //跨浏览器移除事件
function removeHanler(target, eventType, handler) {
  if(target.removeEventListener) { //DOM2 events
    target.removeEventListener(eventType, handler, false);
  } else { //IE
    target.detachEvent("on", eventType, handler);
  }
}

上面代码的实现思路是,首先判断浏览器是否支持DOM2的事件,如果支持,就用addEventListener()进行添加事件,用removeEventListener来移除事件。如果不支持,那么默认就是低版本的ie浏览器了,并使用ie特有的方法。

    乍一看,上面的代码好像已经充分优化了。隐藏的性能问题在于每次函数调用时都会做重复工作——检测浏览器的类型。这是比较消耗性能,特别是你绑定大量事件,反复调用的时候。事实上,这是不必要的,我们只需要判断一次就行的了。因为一旦页面加载完成后,浏览器的类型已经是确定了的,不可能说,现在是IE,然后浏览着浏览着突然就会变成了chrome的了。所以,我们应该对上面代码进行优化,使其只需要检测一次浏览器。有两种方法可以实现只检测一次,下面分别来探讨一下这两种方法。
  第一种是,在第一次调用添加(移除)事件函数的时候,检测并决定使用哪种方法来绑定或者移除事件,然后重写函数,用一个包含正确操作的新的函数覆盖旧的函数,并且在旧的函数最后调用该这个新的函数。上面代码改写后如下:
//添加事件
function addHandler(target, eventType, handler) {   //检测浏览器类型,并且重写addHanler方法
  if(target.addEventListener) { //DOM2
    addHandler = function(target, eventType, handler) {
      target.addEventListener(eventType, handler, false);
    };
  } else { //IE
    addHandler = function(target, eventType, handler) {
      target.attachEvent("on" + eventType, handler);
    };
  }
  
  //调用新的函数
  addHandler(target, eventType, handler);
} //移除事件removeHanler
function removeHandler(target, eventType, handler) {   //检测浏览器类型,并且重写removeHandler方法
  if(target.removeEventListener) { //DOM2
    removeHandler = function(target, eventType, handler) {
      target.removeEventListener(eventType, handler, false);
    };
  } else { //IE
    removeHandler = function(target, eventType, handler) {
      target.detachEvent("on" + eventType, handler);
    };
  }   //调用新的函数
  removeHandler(target, eventType, handler);
}

需要注意的是,我们在两个函数的最后一行,都调用了被重写了的新函数,比如addHandler(target, eventType, handler);和removeHandler(target, eventType, handler);这是必要的,因为我们用新的函数覆盖了旧的函数,必须要在旧的函数里调用新的函数它才会执行一次。

    还有一种优化方法是,提前检测浏览器类型,并把正确的操作函数赋值给一个变量(或者说是使用函数表达式)。我们可以使用一个三目条件运算符(?...:)来实现,代码如下:
//绑定事件
var addHandler = document.body.addEventListener ?
          function(target, eventType, handler) { //DOM2
            target.addEventListener(eventType, handler,false);
          } :
          function(target, eventType, handler) { //IE
            target.attachEvent("on" + eventType, handler);
          };
//移除事件
var removeHandler = document.body.removeEventListener ?
            function(target, eventType, handler) { //DOM2
              target.removeEventListener(eventType, handler, false);
            } :
            function(target, eventType, handler) { //IE
              target.detachEvent("on" + eventType, handler);
            }

这种方法,比前面比前面那种更加的“积极”,因为他是在函数调用之前就已经去检测浏览器类型了,调用的时候马上就可以正确的去绑定事件。

PS:
参考资料:Nicbolas C.Zakas 《High Performance JavaScript》;chapter 8 ;Don’t Repeat Work
该书目前好像只有英文版而还没有中文版的。如果有需要的可以Google一下,下载个电子版的来看一下
 
 
 

JavaScript跨浏览器绑定事件函数的优化的更多相关文章

  1. Javascript跨浏览器的事件对象

    一.跨浏览器的事件对象 var EventUtil = { ///添加事件 addHandler: function (element, type, handler) { if (element.ad ...

  2. js实现一些跨浏览器的事件方法

    用JavaScript实现事件的绑定,移除,以及一些常用的事件属性的获取,时常要考虑到在不同浏览器下的兼容性,下面给出了一个跨浏览器的事件对象: var EventUtil = { on: funct ...

  3. 跨浏览器的事件对象-------EventUtil 中的方法及用法

    什么是EventUti----封装好的事件对象 在JavaScript中,DOM0级.DOM2级与旧版本IE(8-)为对象添加事件的方法不同 为了以跨浏览器的方式处理事件,需要编写一段“通用代码”,即 ...

  4. EventUtil——跨浏览器的事件对象

    . 首页 博客园 联系我 前言:什么是EventUtil?. EventUtil对象全见. addHandler方法. removeHandler方法. event对象与getEvent方法. tar ...

  5. js事件对象--DOM中的事件对象/IE中的事件对象/跨浏览器的事件对象

    事件对象    在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息.包括导致事件的元素.事件的类型,以及其他与特定事件相关的信息.例如,鼠标操作导致的事件对 ...

  6. JavaScript三种绑定事件的方式

    JavaScript三种绑定事件的方式: 1. <div id="btn" onclick="clickone()"></div> // ...

  7. js 跨浏览器实现事件

    我们知道不同的浏览器实现事件是不同的,就比如说我们常见的有三种方法: 1,dom0处理事件的方法,以前的js处理事件都是这样写的. (function () { var p=document.getE ...

  8. js跨浏览器的事件处理函数

    /* 跨浏览器的事件处理函数 */ var EventUtil = { addHandler : function(element,type,handler){ if(element.addEvent ...

  9. 封装常用的Javascript跨浏览器方法

    var EventUntil={ // 跨浏览器的添加事件方法 addHandler:function(element,type,handler){ if(element.addEventListen ...

随机推荐

  1. DOM&BOM

    文档对象模型(Document Object Model) 来源:文档对象模型(Document Object Model)的历史与20世纪90年代末Netscape Navigator和Micros ...

  2. DOS debug 命令的详细用法

    DOS下的DEBUG命令的详细用法       2 推荐 名称 解释 格式 a (Assemble) 逐行汇编 a [address] c (Compare) 比较两内存块 c range addre ...

  3. Oracle function和procedure

    1.返回值的区别 函数有1个返回值,而存储过程是通过参数返回的,可以有多个或者没有 2. 调用的区别,函数可以在查询语句中直接调用,而存储过程必须单独调用. 函数:一般情况下是用来计算并返回一个计算结 ...

  4. 删除掉str上下两行的空白字符(strip())

  5. Proxy --支持的拦截操作篇

    下面是 Proxy 支持的拦截操作一览. 对于可以设置.但没有设置拦截的操作,则直接落在目标对象上,按照原先的方式产生结果. (1)get(target, propKey, receiver) 拦截对 ...

  6. HDU2717-Catch That Cow (BFS入门)

    题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2717 Catch That Cow Time Limit: 5000/2000 MS (Java/O ...

  7. s21day05 python笔记

    s21day05 python笔记 一.昨日内容回顾及补充 回顾 补充 列表独有功能 extend:循环添加到一个列表中 1.users = ['张三',66],people = ['王五',99] ...

  8. lesson4Embedding-fastai

    dense layer:mnist识别中,需要十组dense权重矩阵来计算这十个输出内容,conv矩阵每一个元素乘以另一个矩阵的元素并相加,得到一个值,最后加上sigmoid(softmax在二元情况 ...

  9. 读书笔记--More Effective C++--效率(总结)

    PS: 本文只是总结,具体内容需要去查看More Effective C++--效率部分. 1. 80—20准则 大约 20%的代码使用了 80%的程序资源:大约 20%的代码耗用了大约 80%的运行 ...

  10. 《DSP using MATLAB》Problem 6.17

    代码: %% ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ %% Output In ...