window.onload和<body onload=""/>的区别

243

window.onload事件和body标签的onload事件有什么区别?我应该在何时使用它们,如何正确使用呢?


2
你应该使用双引号来包围属性值。 - Sven Larson
13个回答

232

window.onload = myOnloadFunc<body onload="myOnloadFunc();"> 是使用相同事件的不同方法。使用window.onload 较为不显眼,因为它能将JavaScript代码从HTML中分离出来。

所有常见的JavaScript库,如Prototype、ExtJS、Dojo、JQuery、YUI等,都提供了对文档加载时发生的事件的良好封装。您可以监听窗口的onLoad事件,并对此做出反应,但是只有在所有资源下载完成后才会触发onLoad事件,所以您的事件处理程序直到最后一个大图片被获取后才会执行。在某些情况下,这正是您想要的结果,而在其他情况下,您可能会发现监听DOM何时准备好更合适——这个事件类似于onLoad但是不需要等待图像等资源下载完毕。


62
然而需要注意的是,这两者存在区别。使用内联的onload事件将在全局上下文环境中调用 myOnloadFunc()this会指向window)。而通过JavaScript设置它将使其在元素的上下文环境中执行(this 指向触发事件的元素)。在这种特定情况下,这不会造成影响,但对于其他元素来说则会有所不同。 - mowwwalker
1
@Walkerneo:是的,绝对值得注意。当然,如果需要的话,使用JS库可以重写this所引用的对象。 - Richard Turner
@RichardTurner 你不需要使用库来改变上下文绑定。一个简单的 .bind() 调用就可以实现。 - Kloar
@Kloar,现在你可以这样做,但需要使用MSIE9+。在我回答时更常见的旧版MSIE中,你需要一个polyfill。 - Richard Turner

36

这两种方法并没有区别,但都不应该使用。

在许多浏览器中,window.onload 事件只有在所有图片加载完成后才会触发,这通常不是我们想要的。标准化的浏览器有一个名为 DOMContentLoaded 的事件可以提前触发,但是IE浏览器(截至回答撰写时)不支持该事件。建议使用支持跨浏览器的 DOMContentLoaded 功能的JavaScript库,或查找可用的高质量函数。jQuery的 $(document).ready() 是一个很好的例子。


58
未来的问题:如果没有jQuery会怎样? - Sid
56
如果当前项目中只需要使用库中的一个功能,而 jQuery 又过于臃肿,则该怎么办?(并不是贬低 jQuery,我自己也使用它。只是有时候只需要从库中提取一个功能..) - Bradmage
14
当你说“不受IE支持”时,这是普遍的真相还是只对特定版本的IE有效?自从你写下这个答案以来,浏览器世界发生了很多变化,也许是时候更新一下这个答案了? - Bryan Oakley
8
DOMContentLoaded现在被IE9及以上版本所支持:https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded - Adam
7
来自未来的报道:现在所有主流浏览器都支持DOMContentLoaded事件了。http://caniuse.com/#feat=domcontentloaded - Jose Gómez
显示剩余3条评论

23

window.onload可以在没有body的情况下工作。创建只包含脚本标签的页面并在浏览器中打开它。该页面不包含任何主体,但仍然可以正常工作。

<script>
  function testSp()
  {
    alert("hit");
  }
  window.onload=testSp;
</script>

6
如果你实际上添加了内容(应该在body标签中),没有body标签的HTML是无效的。另外,你的脚本标签缺少type属性。永远不要依赖浏览器修复你的非标准兼容代码!因为浏览器过去或未来可能会以不同的方式或根本不进行修复。 - Kissaki
4
@Kissaki:标准的HTML完全不需要body标签! - Robert Siemer
5
xhtml1规定了<!ELEMENT html (head, body)> [1],而html401则规定了<!ELEMENT HTML O O (%html.content;),同时使用<!ENTITY % html.content "HEAD, BODY"> [2]。html51也规定了对于HTML内容需要一个 head 元素后跟一个 body 元素。[3] 因此,我想所有这些常见/正在使用的HTML标准都要求有一个body标签。 :) - Kissaki
1
@Kissaki 这是XHTML,不是HTML。HTML允许省略开始和结束body标签,以及省略html和head标签,根据其SGML DTD。http://www.w3.org/TR/html401/struct/global.html#edef-BODY 开始标签:可选,结束标签:可选 - OdraEncoded
如果你想特别使用HTML4而不是HTML5,那当然可以。HTML5将符合HTML4的标准,但反之则不然。所以如果你真的只想为过去十年编码,那就继续吧。 - Kissaki
1
@Kissaki:HTML5不再需要脚本类型(如果是JavaScript),你对早期版本是正确的。 - Mark

10

通常情况下,我更喜欢使用<body onload="">事件。我认为尽可能将行为与内容分离会更加清晰。

话虽如此,有时(对我来说通常很少)使用body onload可以略微提高速度。

我喜欢使用Prototype,所以我通常会将类似以下内容放在页面的<head>中:

document.observe("dom:loaded", function(){
  alert('The DOM is loaded!');
});
或者
Event.observe(window, 'load', function(){
  alert('Window onload');
});

以上是我从这里学到的技巧。我非常喜欢在HTML之外附加事件处理程序的概念。

(编辑以更正代码中的拼写错误。)


在什么情况下会更快,为什么? - Kissaki
这个答案似乎非常主观,有很多“我”(“我更喜欢”,“我认为”)。进一步缺乏任何客观和可验证的事实,这基本上支持了这种印象。 - Kissaki
1
考虑到这个答案是6年前发布的,我建议你对它持保留态度。你可以随时更新它或者发表自己更好的答案。 - Mark Biek

8

有关一个客观问题的主观答案太多了。"不显眼"的JavaScript就像旧时规则中从不使用goto一样迷信。编写代码应该有助于您可靠地实现目标,而不是根据某些时髦的宗教信仰。

任何发现以下情况的人:

 <body onload="body_onload();">

过于分散注意力是过于自以为是,说明他们没有把优先事项放在首位。

我通常将JavaScript代码放在单独的.js文件中,但我发现在HTML中挂钩事件处理程序并不麻烦,而且这也是有效的HTML。


39
写不显眼的 JavaScript 有很好的理由。比如说你有一个包含100个页面的Web应用程序,如果你使用 <body onload="body_onload();"> 这种方法而非将其放在每个页面都引入的 JavaScript 文件中,假设因某种原因你需要更改该函数的名称,那么将事件放在已引入的 JavaScript 文件中既使更改变得极为简单,又能节约服务器资源,因为 JavaScript 文件可以被缓存一年(在正确配置的服务器上),而不必一遍又一遍地下载相同的代码。 - Andrew Ensley
21
因为你不愿意了解为什么某些事物被推荐,所以你把这些建议称作“时髦的宗教信仰”吗? - hallvors
6
问题是“这两种方法有什么区别?”并请求推荐哪种更好。您的回答如何回答这个问题? - Richard Turner
1
任何情况下,您在一个地方制作模块化解决方案并应用于大量文件的做法都比将代码添加到每个文件中要好得多。这对于原始构建时间、代码组织目的、可读性和未来编辑都更好。这不是时髦的,实际上是一种旧概念,存在于像Java和C++这样的语言中,现在Web程序员正在接受它作为更好的编码方式。 - Jimbo Jonny
1
现代浏览器中防止XSS攻击的一个好方法是使用内容安全策略禁用所有内联JavaScript。这是不在HTML中使用onload属性的一个相当好的理由。 - Greg Ball

5

window.onload - 在所有DOM元素、JS文件、图片、IFrames、扩展等完全加载后调用。这相当于$(window).load(function() {})

<body onload=""> - DOM加载后只会被调用一次。这相当于$(document).ready(function() {})


1
有人能够提供这个资料吗?我在许多论坛上看到了这个声明,但从未看到过定义它的规范链接。 - crempp
1
@crempp,有body元素全局属性,所以我认为这不是真的。但你可以自己测试一下,看看http://jsbin.com/OmiViPAJ/1/edit。在那里,你可以看到图像的onload事件在body onload事件之前被触发。 - Olaf Dietsche
2
这个答案与其他人的回答相矛盾,你能提供一个来源吗? - Jimmy Breck-McKye
2
jQuery文档中提到:“.ready()方法通常与<body onload="">属性不兼容。”我认为在jQuery中更接近于body.onload的是$(window).load(..),但我认为它们仍然有所不同。 - ccsakuweb
2
这个答案完全错误,不应该有任何赞成票。事实上,这种类型的答案通常被认为是关于“ready”与“onload”事件最大的误解之一。“load”事件在整个文档加载完成后才会触发,包括所有脚本、图像和样式表。“DOMContentLoaded”事件在DOM树构建完成之后但在图像等加载之前触发。它的“DOMContentLoaded”与“document.ready”相当,而不是“load”。 - rism

2

这两种方式没有区别,你可以同时使用它们(但是一次只能用一个)。

但是为了可读性和html代码的整洁性,我总是更喜欢使用window.onload!o]


2

<body onload=""> 应该覆盖 window.onload

使用 <body onload="">document.body.onload 在不同浏览器中可能为 null、undefined 或函数(尽管 getAttribute("onload") 可以相对一致地获取匿名函数体作为字符串)。而当你将一个函数分配给 window.onload 时,window.onload 将在各个浏览器中始终是一个函数。如果这很重要,就使用 window.onload

无论如何,window.onload 更适合将 JS 与您的内容分离。当您可以使用 window.onload 时,没有太多理由使用 <body onload="">

在 Opera 中,window.onload<body onload=""> 的事件目标(甚至 window.addEventListener("load", func, false)) 将是窗口,而不像 Safari 和 Firefox 中那样是文档。但是,'this' 在各个浏览器中都是窗口。

这意味着,在需要时,您应该包装 crud 并使事情保持一致,或者使用一个为您完成此操作的库。


1
如果您正在尝试编写不显眼的JS代码(而您应该这样做),那么您不应该使用<body onload="">
我理解不同的浏览器处理这两个有些不同,但它们的操作方式相似。在大多数浏览器中,如果您定义了两个,其中一个将被忽略。

1

把onload想象成任何其他属性。例如,在输入框上,您可以放置:

<input id="test1" value="something"/>

或者你可以打电话:

document.getElementById('test1').value = "somethingelse";

onload属性的作用方式相同,只是它将函数作为其值而不是像value属性一样的字符串。这也解释了为什么你只能“使用其中之一”——调用window.onload会重新分配body标签的onload属性的值。

此外,就像其他人在这里说的那样,通常最好将样式和JavaScript与页面内容分开,这就是为什么大多数人建议使用window.onload或像jQuery的ready函数的原因。


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