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. 写的一个ORACLE存储过程小练习

    CREATE OR REPLACE PROCEDURE PRO_1112(O_NOTE OUT NUMBER,O_RESULT OUT VARCHAR2)ASV_NO NUMBER(20);V_NOT ...

  2. L268 A terrifying look at the consequences of climate change

    Climate change is a devilish problem for humanity: at once urgent and slow-moving, immediate and dis ...

  3. 18-09-27 pandas 学习02

    如何系统的学习python 中有关数据分析和挖掘相关的库?什么是系统的学习?系统的学习就是一个先搭建只是框架体系,然后不断填充知识看,不断更新迭代的过程. Pandas,numpy,scipy,mat ...

  4. Sample Credential Providers

        Windows Vista Sample Credential Providers Overview Contents Terms of Use Release Notes SampleCre ...

  5. python sub替换方法

    命令:re.sub(pattern, repl, string, count=0, flags=0) re.sub 用于替换字符串的匹配项.如果没有匹配到规则,则原字符串不变. 第一个参数:规则 第二 ...

  6. python day08作业答案

    1. a f=open('11.txt','r',encoding='utf-8') a=f.read() print(a) f.flush() f.close() b. f=open('11.txt ...

  7. POJ 2001 Shortest Prefixes(字典树)

    Description A prefix of a string is a substring starting at the beginning of the given string. The p ...

  8. 【Python】socket编程-2

    #练习3:TCP协议+while循环 服务端: import socket #socket模块 import sys reload(sys) sys.setdefaultencoding(" ...

  9. 【Python】多进程-共享变量(Value、string、list、Array、dict)

    #练习:未使用共享变量 from multiprocessing import Process def f(n, a): n = 3.1415927 for i in range(len(a)): a ...

  10. scrapt中的数据提取,采用js2xml库

    这个一个爬去美团的例子,应为数据都是在script中,小心封ip,尽量少运行. 先导入库几个库 import requests from bs4 import BeautifulSoup from l ...