window.onload 在 DOM 加载前触发的问题(JavaScript)

13

我遇到了关于 window.onloaddocument.onload 事件的问题。所有我看到的信息都告诉我这些事件只有在DOM完全加载完成后才会被触发,但是似乎我的情况并非如此:

我在Chrome 4.1.249.1036 (41514)和IE 8.0.7600.16385上尝试了下面这个简单的页面,结果相同:它们都显示了消息"失败了!",说明myParagraph没有被加载(因此DOM似乎不完整)。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
    <head>
        <script type="text/javascript">
            window.onload = doThis();
            // document.onload gives the same result

            function doThis() {
                if (document.getElementById("myParagraph")) {
                    alert("It worked!");
                } else {
                    alert("It failed!");
                }
            }
        </script>
    </head>

    <body>
        <p id="myParagraph">Nothing is here.</p>
    </body>
</html>
我使用更加复杂的脚本,存储在一个外部的 .js 文件中,但这个例子可以说明问题。我可以通过设置 window.onload 定时器半秒钟来运行 doThis() 以使其工作,但这似乎是一种不太优雅的解决方案,并没有回答为什么 window.onload 看起来不像大家所说的那样工作的问题。另一种解决方案是设置一个定时器来检查DOM是否已加载,如果没有则再过半秒重新调用自身(因此它将一直检查直到DOM被加载),但我觉得这种方法过于复杂。

有更合适的事件可以使用吗?


1
我看到的第一个错误是你赋值了[函数结果]而不是[函数]本身。你能看到doThis()是一个语句,在评估后返回未定义,因为doThis没有return运算符。window.onload = doThis;就可以完成任务。请注意,这里没有括号。 - Dan
2
@DavidMason W3Schools是一个信息质量较差的来源。他们与W3C没有任何关联。不要将w3schools视为权威信息来源,把它们当作烦人的链接,当你在寻找真正的参考网站时需要跳过它们。 - doug65536
1
@doug65536 现在的我完全同意。我推荐w3fools.com给任何不确定的人。这些天我倾向于直接查阅developer.mozilla.org获取高质量的信息,如果那里找不到我需要的内容,我会进行更广泛的搜索(通常是当我尝试做一些荒谬的事情时)。我对过去的自己发布了那篇文章感到非常尴尬...但是我可以删除它!嗯,互联网上少了一个对w3schools的幼稚参考 :) 感谢你发现这个问题。 - David Mason
5个回答

10

当窗口加载时,页面主体仍未加载,因此您应该按照以下方式更正代码:

<script type="text/javascript">
    window.onload = function(){
        window.document.body.onload = doThis; // note removed parentheses
    };

    function doThis() {
        if (document.getElementById("myParagraph")) {
            alert("It worked!");
        } else {
            alert("It failed!");
        }
    }
</script>

经过测试,在FF/IE/Chrome中都能够工作,尽管我们正在考虑如何处理document.onload

正如已经提到的那样,使用JavaScript框架将是一个更好的选择。


谢谢,这似乎解决了我的问题,并解决了我认为是同一个问题的递归,即在知道body是否已成功加载之前将某些内容附加到body.onload事件上。现在我有了“它起作用了!”的消息弹出,可以继续严格保持我的脚本和标记分离。 - David Mason
请注意,使用此方法处理两个脚本可能会相互覆盖。现在我倾向于使用以下代码:document.addEventListener("DOMContentLoaded", function(event) { console.log("DOM fully loaded and parsed"); });参考链接:https://developer.mozilla.org/en-US/docs/Web/Reference/Events/DOMContentLoaded - David Mason
@DavidMason 在我的测试中,DomContentLoaded比onload先加载。有时在load事件和DOMContentLoaded事件中,speechSynthesis.getVoices()是一个空数组。是否有更晚的事件? - 1.21 gigawatts
@1.21gigawatts 我不知道关于你的 speechSynthesis.getVoices() 应该如何加载,所以寻找内容加载可能不是正确的方法 - 如果有一个脚本正在加载它,那么你需要让尝试使用它的脚本出现在那个脚本之后(并且不将那个脚本标记为异步)。 - David Mason
@DavidMason SpeechSynthesis是Windows对象上的一个属性。getVoices调用获取文本到语音的声音列表。有时它是空的。简单的页面刷新后就可以使用了。我为了解决这个问题,首先在dom内容加载和加载时进行调用,并将其分配给一个数组,然后稍后如果用户访问声音数组,我会检查数组是否为空并再次调用它。这似乎可以解决问题。https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis - 1.21 gigawatts
仅供记录,这些答案或评论中提到的任何内容都没有对我起作用。无论我尝试什么,"load"触发器总是在页面主体出现之前大约2秒钟就会触发。我只好在"load"触发器后添加3秒的超时等待。虽然这种方法不太完美,但总比没有好。 - UncaAlby

10
只需使用 window.onload = doThis; 而不是 window.onload = doThis();

请参考此链接了解更多信息:https://dev59.com/9Woy5IYBdhLWcg3wA5aC - Cymbals

9
重要的是要了解,()是一个运算符,就像+&&一样。 ()接受一个函数并调用它。
所以在这种情况下,doThis是一个函数对象,()是调用函数的运算符。将doThis()组合在一起调用doThis,执行它,并计算doThis的返回值。
因此,window.onload = doThis()基本上是将doThis的返回值分配给window.onload
因此,要修复它,您需要引用函数本身,而不是调用它。
window.onload = doThis

2
这应该是答案。 - Jack G

1
你尝试过使用JavaScript库吗?例如jQuery和它的$(document).ready()函数:
  $(document).ready(function() {
      // put all your jQuery goodness in here.
  });

1
谢谢,我会在本周检查一下。我仍然担心没有与 DOM 相关联的事件可以可靠地告诉我 DOM 已加载,除非使用第三方脚本。 - David Mason
1
仅为此目的添加库绝对是过度设计 - 库下载会增加延迟和数据传输,可能只能为您节省一些字符。jQuery 特别沉重。 话虽如此,如果您已经在使用库来处理其他事情,那么使用它来处理将函数附加到 dom-ready 事件上可能没有或很少有害处。 - David Mason
@David Mason 我完全同意。在大多数情况下,我发现 jQuery 会使页面加载时间增加一倍。 - James Walker
如果您从CDN加载jquery(或任何其他流行的JavaScript库),那么您的浏览器很有可能已经在其缓存中拥有js文件(因为访问其他网站而产生),因此加载时间不应该明显增加。@JamesWalker - M4N

1

这取决于您放置 onload 函数的位置(头部标签或正文标签或更往下),使用内部事件绑定在不同的浏览器中看起来略有不同。

另请参见window.onload vs document.onload


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接