《JavaScript精粹(修订版)》——1.8 让不同的脚本在同一页面中协同工作

本节书摘来自异步社区《JavaScript精粹(修订版)》一书中的第1章,第1.8节,作者:【英】Edwards, J. , 【澳】Adams, C.著,更多章节内容可以访问云栖社区“异步社区”公众号查看

1.8 让不同的脚本在同一页面中协同工作

如果几个脚本总是不能协同工作,那么很有可能是因为这些脚本试图对某给定元素的同一种事件处理赋予了不同的处理函数。因为每个元素对每个事件只有一个处理方法,所以同一个事件的处理会被不同的处理函数重复地替换。

方 法
通常应该怀疑的是window对象的load事件处理,因为在同一页面中,只有一个脚本能够使用这个事件;如果两个或者多个脚本尝试使用该事件,那么最后一个脚本会将前面脚本的处理函数覆盖掉。

可以在load事件处理函数中调用多个函数,如下:

window.onload = function()
{
  firstFunction();
  secondFunction();
}

不过,如果这样做,就必须受限于在load事件的处理函数中完成所有的任务。另一个好一点的解决方案是提供一个函数,可以增加对load事件的处理而不与其他已经添加的处理函数冲突。

使用下面的函数,可以添加任意数量的load事件的处理函数,而无需担心它们发生冲突:

文件:add-load-listener.js

function addLoadListener(fn)
{
  if (typeof window.addEventListener != 'undefined')
  {
    window.addEventListener('load', fn, false);
  }
  else if (typeof document.addEventListener != 'undefined')
  {
    document.addEventListener('load', fn, false);
else if (typeof window.attachEvent != 'undefined')
{
  window.attachEvent('onload', fn);
}
else
{
  var oldfn = window.onload;
  if (typeof window.onload != 'function')
  {
    window.onload = fn;
  }
  else
  {
    window.onload = function()
      {
        oldfn();
        fn();
      };
    }
  }
}

这样,就可以随心所欲地增加新的load事件处理函数了,如下:

addLoadListener(firstFunction);
addLoadListener(secondFunction);
addLoadListener(twentyThirdFunction);

讨 论
JavaScript包括了给事件增加或删除监听器的方法,看上去有点儿像普通的事件处理,但却允许多个监听器订阅同一个元素的同一个事件的消息。但是,在Internet Explorer中这种监听器的语法与在其他浏览器中的语法完全不同,IE使用一种独有的方式,而其他浏览器则完全按照W3C标准来实现。开发者经常处于这种折磨之中,在第13章将会讨论有关的细节。

W3C标准方法叫做addEventListener:

window.addEventListener('load', firstFunction, false);
IE的方法叫做attachEvent:

window.attachEvent('onload', firstFunction);
正如您所看到的,标准的创建方法是,直接使用事件的名字(没有on前缀),事件发生时需要调用的函数以及一个用于控制事件传递的参数放在事件名字的后面(第13章会有更详细的讨论)。IE的方法则使用事件处理者的名字(前面带有一个on前缀),需要调用的函数的名字放在其后。

在将代码组织到一起的时候,还需要测试一下试图调用的方法是否存在。可以用JavaScript的typeof操作符,它可以区分数据的不同类型(例如字符串、数字、布尔值、对象、数组、函数或者未定义类型)。一个不存在的方法会返回未定义类型。

if (typeof window.addEventListener != 'undefined')
{
  ┆支持window.addEventListener
}

还有一点稍稍复杂的地方:在Opera中,load事件可以激发来自文档对象的事件监听器,却不能激发来自窗口对象的监听器。不过如果只使用文档对象,这样的代码在老版本的Mozilla浏览器中(例如Netscape 6)又不能工作。为了处理这种问题,还必须测试一下window.addEventListener,然后是document.addEventListener,最后才是window.attachEvent。

最后,对于那些根本不支持这些方法的浏览器(例如Mac IE 5),备用的方案是使用老式的链式事件处理方式,这样在事件发生时事件处理函数仍能被调用。可以动态地创建一个新的事件处理函数,当事件发生时,先调用老的事件处理函数,再调用新的事件处理函数1。

文件:add-load-listener.js (excerpt)

var oldfn = window.onload;
if (typeof window.onload != 'function')
{
 window.onload = fn;
}
else
{
 window.onload = function()
 {
  oldfn();
  fn();
 };
}

如果您现在对这些代码怎样工作还不太理解,不用担心,后续章节还会讨论更多的细节。后面大家会了解到事件监听器不仅适用于load事件,也适用于任何事件驱动的脚本。

上一篇:混合云存储构建VMware虚拟化平台


下一篇:C/C++ 表达式求值的example