window.onload与document.onload的区别

890

哪个更受广泛支持:window.onload 还是 document.onload


3
MDN文档解释了这些window事件:onloadDOMContentLoaded。使用示例:window.addEventListener('DOMContentLoaded', callback)。截至2019年中期,与所有主要浏览器兼容。 - Craig Hicks
即使在今天的Firefox 75.0中,对我而言,window.onloaddocument.onload仍然是不同的! window.onload似乎发生在之后,并且比document.onload加载了更多内容!(一些使用window的东西在使用document时无法正常工作!这也适用于document.onreadstatechange 'complete'!) - Andrew
9个回答

882

他们什么时候开火?

window.onload

  • 默认情况下,它会在整个页面加载完成时触发,包括其内容(图像、CSS、脚本等)。

在某些浏览器中,它现在接管了document.onload的角色,并在DOM准备就绪时触发。

document.onload

  • 当DOM准备就绪时调用,这可能在加载图像和其他外部内容之前。

它们的支持情况如何?

window.onload似乎是最广泛支持的。事实上,一些最现代的浏览器已经在某种程度上用window.onload替代了document.onload

浏览器支持问题很可能是为什么许多人开始使用类似jQuery的库来处理文档准备就绪检查的原因,如下所示:

$(document).ready(function() { /* code here */ });
$(function() { /* code here */ });

为了历史记��而言,window.onloadbody.onload的区别:

在codingforums上曾经有人问过类似的问题,关于使用window.onload还是body.onload。结果似乎是应该使用window.onload,因为将结构与行为分离是一个好习惯。


29
实际上,该语句似乎是针对window.onload<body onload="">之间的选择,这完全不同(在这种情况下,“将结构与行为分离”更有意义)。并不是说答案是错的,但它的基础是错误的。 - Vala
2
那句引文的语法太糟糕了...难道不需要一些(标记)编辑吗? - Kheldar
@Thor84no,我终于找到时间再次查看了这个问题。我进行了一些改进。 - Josh Mein
@Kheldar,我决定转述这句话,因为它相当粗糙。 - Josh Mein
1
我认为这个答案需要一些更新。在MDN上,它现在仅被归类为“DOMContentLoaded”和“load”事件。我没有看到这个答案描述的documentwindow前缀之间的区别。请检查问题下面第一个评论的链接。 - Rick
显示剩余6条评论

303

一般的想法是,当文档的窗口window.onload准备好展示并且文档内的 markup 代码建立起来的DOM tree document.onload完成时会触发。

理想情况下,订阅DOM-tree events可以通过JavaScript进行屏幕外操纵而几乎不产生CPU负载。相反,window.onload在多个外部资源尚未请求、解析和加载时可能需要等待一段时间才会触发

►测试场景:

为了观察区别以及您所选浏览器如何实现上述事件处理程序,请将以下代码插入到文档的-<body>-标签中。

<script language="javascript">
window.tdiff = []; fred = function(a,b){return a-b;};
window.document.onload = function(e){ 
    console.log("document.onload", e, Date.now() ,window.tdiff,  
    (window.tdiff[0] = Date.now()) && window.tdiff.reduce(fred) ); 
}
window.onload = function(e){ 
    console.log("window.onload", e, Date.now() ,window.tdiff, 
    (window.tdiff[1] = Date.now()) && window.tdiff.reduce(fred) ); 
}
</script>

►结果:

以下是在Chrome v20(以及大多数当前浏览器)中可观察到的行为。

  • 没有document.onload事件。
  • <body>内声明onload会触发两次,而在<head>内声明则会被视为document.onload
  • 计算并根据计数器状态进行操作可以模拟这两种事件行为。
  • 或者在HTML的<head>元素内声明window.onload事件处理程序。

►示例项目:

以上代码摘自此项目的代码库(index.htmlkeyboarder.js)。


有关窗口对象的事件处理程序列表,请参阅MDN文档。


239

添加事件监听器

<script type="text/javascript">
  document.addEventListener("DOMContentLoaded", function(event) {
      /* 
        - Code to execute when only the HTML document is loaded.
        - This doesn't wait for stylesheets, 
          images, and subframes to finish loading. 
      */
  });
</script>

2017年3月更新

1. 纯 JavaScript

window.addEventListener('load', function() {
    console.log('All assets are loaded')
})

2 jQuery

$(window).on('load', function() {
    console.log('All assets are loaded')
})


24
"DOMContentLoaded"事件在初始HTML文档已被完全加载和解析后触发,而不需要等待样式表、图像和子框架完成加载。因此,您似乎关于所有内容都在此事件中加载是不正确的。 - ProfK
3
@ProfK,感谢您的反馈。您可以尝试使用window.addEventListener('load', function() {...})。我也已经更新了我的回答。 - Aakash
10
我喜欢这个答案的原因是它提供了一个普通的 JavaScript 解决方案。考虑到 jQuery 经常作为唯一答案被给出,人们可能认为它已经内置在所有浏览器中了。 - Dave Land
当该死的jQuery加载时间过长并且出现$未找到时,会出现双重问题。我认为$(window).ready类型的解决方案永远不能被信任。 - Shayne
2
我今天在Chrome上尝试了两种方法,它没有等待CSS和字体。 - movAX13h
这并没有回答问题。 - undefined

113
根据分析HTML文档-结束
  1. 浏览器解析HTML源代码并运行延迟脚本。

  2. 当所有HTML已解析并运行时,会在document上派发DOMContentLoaded事件。该事件冒泡到window

  3. 浏览器加载延迟加载的资源(如图像)。

  4. window上派发load事件。

因此,执行顺序将是
  1. 捕获阶段中windowDOMContentLoaded事件侦听器
  2. documentDOMContentLoaded事件侦听器
  3. 冒泡阶段中windowDOMContentLoaded事件侦听器
  4. windowload事件侦听器(包括onload事件处理程序)

一个在document中的气泡load事件监听器(包括onload事件处理程序)不应该被调用。只有捕获load监听器可能会被调用,但由于子资源(如样式表)的加载而不是由于文档本身的加载。

window.addEventListener('DOMContentLoaded', function() {
  console.log('window - DOMContentLoaded - capture'); // 1st
}, true);
document.addEventListener('DOMContentLoaded', function() {
  console.log('document - DOMContentLoaded - capture'); // 2nd
}, true);
document.addEventListener('DOMContentLoaded', function() {
  console.log('document - DOMContentLoaded - bubble'); // 2nd
});
window.addEventListener('DOMContentLoaded', function() {
  console.log('window - DOMContentLoaded - bubble'); // 3rd
});

window.addEventListener('load', function() {
  console.log('window - load - capture'); // 4th
}, true);
document.addEventListener('load', function(e) {
  /* Filter out load events not related to the document */
  if(['style','script'].indexOf(e.target.tagName.toLowerCase()) < 0)
    console.log('document - load - capture'); // DOES NOT HAPPEN
}, true);
document.addEventListener('load', function() {
  console.log('document - load - bubble'); // DOES NOT HAPPEN
});
window.addEventListener('load', function() {
  console.log('window - load - bubble'); // 4th
});

window.onload = function() {
  console.log('window - onload'); // 4th
};
document.onload = function() {
  console.log('document - onload'); // DOES NOT HAPPEN
};


1
我运行了你的片段,确实发生了 document - load - capture,这与我在搜索中期望的文档加载未发生的情况相反。奇怪的是,它是不一致的。有时会出现,有时不会,有时会出现两次,但从来没有发生过 document - load - bubble。我建议不要使用 document load - erroric
@erroric 好观点。我没有考虑到外部资源会派发“load”事件。该事件不会冒泡,因此通常在文档上不会检测到它,但应在捕获阶段检测到它。这些条目指的是 <style><script> 元素的加载。我认为 Edge 正确地显示了它们,而 Firefox 和 Chrome 错了。 - Oriol
谢谢Oriol,useCapture选项让我学到了新东西。 - Paul Watson
感谢您总结了来自w3的解析和渲染流程。我想知道在第4步之后,一旦“load”事件被触发,还会发生什么?我注意到在我的浏览器上,有时在触发加载事件后仍然会获取一些对象,尽管我根本没有触摸或与页面交互。您知道那些对象叫什么吗?“非阻塞渲染对象”? - weefwefwqg3

14
在Chrome中,window.onload与不同,然而它们在Firefox(版本35.0)和IE(版本11)中是相同的。您可以通过以下代码片段进行探索:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <!--import css here-->
        <!--import js scripts here-->

        <script language="javascript">

            function bodyOnloadHandler() {
                console.log("body onload");
            }

            window.onload = function(e) {
                console.log("window loaded");
            };
        </script>
    </head>

    <body onload="bodyOnloadHandler()">

        Page contents go here.

    </body>
</html>

在Chrome控制台中,您会看到"窗口已加载"(首先出现)和"body onload"。 但是,在Firefox和IE中,您只会看到"body onload"。如果您在IE和FF的控制台中运行"window.onload.toString()",您会看到:

"function onload(event) { bodyOnloadHandler() }"

这意味着赋值"window.onload = function(e)..."被覆盖了。


9

简而言之

  • window.onload 不受IE 6-8的支持
  • document.onload 不受任何现代浏览器的支持(事件永远不会被触发)

window.onload   = () => console.log('window.onload works');   // fired
document.onload = () => console.log('document.onload works'); // not fired


9

window.onloadonunloaddocument.body.onloaddocument.body.onunload的快捷方式。

document.onload和所有HTML标签上的onload处理程序似乎已被保留,但从未触发。

'onload'在文档中 -> true


5

window.onload 和 body.onload 在大多数情况下是相同的。但在IE中,body.onload 变成了 window.onload。


1

Window.onload是标准,但是PS3中的网络浏览器(基于Netfront)不支持window对象,因此您无法在那里使用它。


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