添加多个onload处理程序

时间:2010-12-29 22:13:39

标签: javascript event-handling onload

我有两个js文件,每个文件都有自己的window.onload处理程序。根据我如何将两个onload处理程序附加到window对象,我在第二个处理程序上得到了不同的行为。

更具体地说,这是我的html文件:

<html>
<head>
 <title>Welcome to our site</title>
 <script type="text/javascript" src="script1.js"> </script>
 <script type="text/javascript" src="script2.js"> </script>
</head>
<body id="pageBody">
 <h2 align="center"> 
  <a href="http://www.whatever.com" id="redirect"> Wellcome to our site... c'mon in! </a> 
 </h2>
</body>
</html>

它加载两个js文件,script1.js和script2.js。

这两个脚本的版本导致(至少是我)意外行为。

Script1.js:

window.onload = initAll1(); // attach first onload handler

function initAll1() {
 alert("initAll1");
 document.getElementById("redirect").onclick = foo; // attach an onclick handler
}

function foo() {
 alert("we are in foo"); 
 return false;
}

Script2.js:

addOnloadHandler(initAll2); // with this we should attach a second onload handler

function initAll2() {
 alert("initAll2");
 if (linkHasOnclickHandler(document.getElementById("redirect"))) {
  alert("correct!"); 
 }
 else {
  alert("wrong!");
 }
}

function addOnloadHandler (newFunction) {
 var oldevent = window.onload;
 if (typeof oldevent == "function") {
  window.onload = function() {
      if (oldevent) {
          oldevent();
      }
   newFunction();
  };
 }
 else {
      window.onload = newFunction;
 }
}

function linkHasOnclickHandler() {
 var oldevent = document.getElementById("redirect").onclick;
 if (typeof oldevent == "function") {
  return true;
 }
 else {
  return false;
 }
}

在Script2.js中,我尝试使用函数addOnloadHandler()以一种很好的非侵入方式添加第二个onload处理程序。此函数不会对是否已将任何onload处理程序附加到窗口对象进行任何假设。它是非侵入性的,因为它应该添加新的处理程序而不删除以前的处理程序。

问题在于,当加载addOnloadHandler()时,initAll2()无法检测到document.getElementById(“redirect”)已经将foo()作为onclick事件处理程序附加的事实(请参阅initAll1()) 。警告信息“错误!”被触发,这对我来说似乎是错误的行为。

当我忘记addOnloadHandler()并使用以下命令附加Script1.js中的两个onload处理程序时:

window.onload = function () {initAll1(); initAll2();};

然后一切都按预期工作,initAll2()启动“正确!”警报信息。

addOnloadHandler()有什么问题吗?任何人都可以使它工作吗?我真的想用它而不是第二种方法。

谢谢!

4 个答案:

答案 0 :(得分:5)

以防未来的人发现这一点,并且当对象本身不支持addEventListenerattachEvent或其他形式的监听器堆叠时,正在寻找使用多个事件处理程序的方法 - 即它是一个定制的对象,执行得很糟糕。然后,您可以执行以下操作:

object.onload = (function(pre){
  return function(){
    pre && pre.apply(this,arguments);
    /// do what you need for your listener here
  }
})(object.onload);

每次使用上面的代码时,前一个onload侦听器都作为参数传入,当您的新侦听器被触发时,它首先运行旧侦听器 - 这意味着您可以像这样堆叠许多侦听器,如果您愿意。但是,只有在上面的代码始终用于向对象添加侦听器时,这才会起作用。如果其他地方被简单的覆盖,那么你所有的努力都将被取消:

object.onload = function(){}

作为编码员的注释,如果要实现库,插件或构造函数,其他编码人员可能会接管您的工作。请为多个事件监听器编写代码。 这真的不那么难。

答案 1 :(得分:2)

您需要查看addEventListenerattachEvent,它们是addOnloadHandler的原生实现。

答案 2 :(得分:1)

PPK对addEventListener的引用解释了这一点非常好:

http://www.quirksmode.org/js/events_advanced.html

答案 3 :(得分:1)

感谢您的回答!

我使用addEventListener和attachEvent重写了我的script2.js,如下所示:

//addOnloadHandler(initAll1); // it works only when uncommenting this
addOnloadHandler(initAll2);

function initAll2() {
    alert("initAll2");
    if (linkHasOnclickHandler(document.getElementById("redirect"))) {
        alert("correct!"); 
    }
    else {
        alert("wrong!");
    }
}

function addOnloadHandler(newFunction) {    
    if (window.addEventListener) { // W3C standard
        window.addEventListener('load', newFunction, false); // NB **not** 'onload'
    }    
    else if (window.attachEvent) { // Microsoft
        window.attachEvent('onload', newFunction);
    }
}

function linkHasOnclickHandler(element) {
    var oldevent = document.getElementById("redirect").onclick;
    if (typeof oldevent == "function") {
        return true;
    }
    else {
        return false;
    }
}

正如您所看到的,addOnloadHandler()已使用您提到的本机实现进行了重写。我没有触及script1.js。

结果代码仍然不起作用(即显示“错误!”警告消息)。它只有在我通过取消注释script2.js中的第一行代码来注册onload initAll1()处理程序两次时才有效。

显然,混合

window.onload = handler1;

window.addEventListener('load', handler2, false);

window.attachEvent('onload', handler2);

效果不好。

有没有办法解决这个问题并不意味着触及script1.js?

万一你想知道为什么我不想触摸script1.js,原因是我希望我的代码(script2.js)也可以在其他项目中重用,无论每个项目中哪个其他js文件使用。因此,它应该与script1.js中使用的每种可能的事件处理注册方法一起使用。

再次感谢您的帮助!