添加多个 onload 处理程序

2022-01-15 00:00:00 event-handling javascript onload

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

I have two js files, each one with its own window.onload handler. Depending on how I attach the two onload handlers to the window object I get a different behaviour on the second handler.

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

More specifically, here is my html file:

<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.

It loads two js files, script1.js and script2.js.

这是导致(至少对我而言)意外行为的这两个脚本的版本.

Here is the version of these two scripts that leads to the (at least by me) unexpected behaviour.

Script1.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:

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 处理程序做任何假设.它是非侵入性的,因为它应该添加新的处理程序而不删除以前的处理程序.

In Script2.js I tried to add the second onload handler in a nice noninvasive way using function addOnloadHandler(). This function does not make any assumption on whether there is already any onload handler attached to the window object. It is noninvasive because it should add the new handler without deleting previous ones.

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

The thing is that when loaded with addOnloadHandler(), initAll2() is not capable of detecting the fact that document.getElementById("redirect") already has foo() attached as an onclick event handler (see initAll1()). The alert message "wrong!" is triggered, which to me seems to be the wrong behaviour.

当我忘记 addOnloadHandler() 并在 Script1.js 中附加两个 onload 处理程序时,使用:

When I forget about addOnloadHandler() and attach both onload handlers in Script1.js using:

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

然后一切都按预期工作,并且 initAll2() 启动正确!"提示信息.

then everything works as expected, and initAll2() launches the "correct!" alert message.

addOnloadHandler() 有什么问题吗?有人可以让它工作吗?我真的很想用它来代替第二种方法.

Is there something wrong about addOnloadHandler()? Could anybody make it work? I would really like to use it instead of the second method.

谢谢!

推荐答案

以防万一将来人们发现这个,并且正在寻找一种在对象本身不支持时使用多个事件处理程序的方法 addEventListenerattachEvent 或某种其他形式的监听器堆栈——即它是一个定制对象,实施不当.然后您可以执行以下操作:

Just in case future people find this, and are looking for a way to use multiple event handlers when the object itself doesn't support addEventListener, attachEvent or some other form of listener stacking - i.e. it is a bespoke object, badly implemented. Then you can do the following:

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

每次您使用上述代码时,前一个 onload 侦听器都会作为参数传入,当您的新侦听器被触发时,它会首先运行旧侦听器 - 这意味着您可以像这样堆叠许多侦听器, 如果你愿意.但是,这仅适用于始终使用上述代码向您的对象添加侦听器的情况.如果在其他地方被简单的覆盖,您所有的辛勤工作都将付诸东流:

Each time you use the above code the previous onload listener is passed in as an argument, and when your new listener is triggered it runs the old listener first - meaning you can stack many listeners like this, if you so wish. However, this will only work for as long as the above code is always used to add listeners to your object. All your hard work will be undone if somewhere else it is overridden with a simple:

object.onload = function(){}

作为编码人员的说明,如果您要实现库、插件或构造函数,则其他编码人员可能会接管您的工作.请为多个事件侦听器编写代码.真的没那么难.

As a note to coders, if you are to implement a library, plugin or constructor, and it is possible other coders will take over your work. Please, please code the ability for multiple event listeners. It's really not that difficult.

相关文章