当页面 DOM 加载时(但在 window.onload 之前)收到通知
-
09-06-2019 - |
题
我知道有一些方法可以在页面正文加载时收到通知(在加载所有图像和第 3 方资源之前,这会触发 窗口加载 事件),但每个浏览器都不同。
有没有一种确定的方法可以在所有浏览器上执行此操作?
目前我所知道的有:
DOM内容已加载 :在 Mozilla、Opera 9 和最新的 WebKit 上。这涉及到向事件添加侦听器:
document.addEventListener( "DOMContentLoaded", [初始化函数], false );
延迟脚本:在 IE 上,您可以发出带有 @defer 属性的 SCRIPT 标记,该标记仅在 BODY 标记关闭后可靠地加载。
轮询:在其他浏览器上,您可以继续轮询,但是是否有一个标准的轮询,或者您需要在每个浏览器上执行不同的操作?
我希望能够不使用 document.write 或外部文件。
这可以简单地通过 jQuery 完成:
$(document).ready(function() { ... })
但是,我正在编写一个 JS 库,不能指望 jQuery 总是在那里。
解决方案
没有跨浏览器的方法来检查 DOM 何时准备好——这就是像 jQuery 这样的库存在的原因,以抽象出令人讨厌的不兼容性。
Mozilla、Opera 和现代 WebKit 支持 DOMContentLoaded
事件。IE 和 Safari 需要一些奇怪的技巧,例如滚动窗口或检查样式表。血淋淋的细节包含在 jQuery 中 bindReady()
功能。
其他提示
我找到了这个页面,它显示了一个紧凑的独立解决方案。它似乎适用于所有浏览器,并解释了如何:
YUI 使用三个测试来做到这一点:对于 Firefox 和最近的 WebKit,会触发 DOMContentLoaded 事件。对于较旧的 Safari,document.readyState 会一直监视,直到它变为“已加载”或“完成”。对于 IE,会创建一个 HTML <P> 标签,并调用“doScroll()”方法,如果 DOM 未准备好,该方法会出错。来源为 雅虎.util.事件 显示 YUI 特定的代码。在 Event.js 中搜索“doScroll”。
使用像 jQuery 这样的库将为您节省无数时间的浏览器不一致问题。
在这种情况下,使用 jQuery 你可以
$(document).ready ( function () {
//your code here
});
如果您好奇,您可以查看源代码以了解它是如何完成的,但是在当今时代,当库作者为您完成了所有痛苦的工作时,我认为任何人都不应该重新发明这个轮子。
只需取 jQuery 中的相关代码即可,John Resig 已经在 jQuery 中涵盖了此问题的大部分基础知识。
为什么不是这个:
<body>
<!-- various content -->
<script type="text/javascript">
<!--
myInit();
-->
</script>
</body>
如果我理解正确的话,myInit 将在浏览器在页面中点击它时立即执行,这是正文中的最后一件事。
您正在寻找的精美跨浏览器解决方案...不存在...(想象一下一大群人说“啊啊……”的声音)。
Dom内容已加载 这就是你最好的选择。你仍然需要 polling
IE-oldies 的技术。
- 尝试使用addEventListener;
- 如果不可用(显然是 IE),请检查框架;
- 如果不是框架,则滚动直到没有错误抛出(轮询);
- 如果是框架,则使用IE事件document.onreadystatechange;
- 对于其他不支持的浏览器,请使用旧的 document.onload 事件。
我在以下位置找到了以下代码示例 javascript.info 您可以使用它来覆盖所有浏览器:
function bindReady(handler){
var called = false
function ready() {
if (called) return
called = true
handler()
}
if ( document.addEventListener ) { // native event
document.addEventListener( "DOMContentLoaded", ready, false )
} else if ( document.attachEvent ) { // IE
try {
var isFrame = window.frameElement != null
} catch(e) {}
// IE, the document is not inside a frame
if ( document.documentElement.doScroll && !isFrame ) {
function tryScroll(){
if (called) return
try {
document.documentElement.doScroll("left")
ready()
} catch(e) {
setTimeout(tryScroll, 10)
}
}
tryScroll()
}
// IE, the document is inside a frame
document.attachEvent("onreadystatechange", function(){
if ( document.readyState === "complete" ) {
ready()
}
})
}
// Old browsers
if (window.addEventListener)
window.addEventListener('load', ready, false)
else if (window.attachEvent)
window.attachEvent('onload', ready)
else {
var fn = window.onload // very old browser, copy old onload
window.onload = function() { // replace by new onload and call the old one
fn && fn()
ready()
}
}
}
这工作得很好:
setTimeout(MyInitFunction, 0);
使用 setTimeout 可以很好地工作,尽管它的执行时间取决于浏览器。如果您传递零作为超时时间,浏览器将在事情“解决”时执行。
这样做的好处是您可以拥有很多这样的事件,并且不必担心链接 onLoad 事件。
setTimeout(myFunction, 0);
setTimeout(anotherFunction, 0);
setTimeout(function(){ doSomething ...}, 0);
ETC。
它们都会在文档加载完成时运行,或者如果您在文档加载后设置一个,它们将在脚本运行完成后运行。
它们的运行顺序尚未确定,并且可能会在浏览器之间发生变化。所以你不能指望 myFunction
之前正在运行 anotherFunction
例如。