如何在没有框架的情况下检查 DOM 是否准备就绪?

这个问题就像这里和网络上无数的其他问题一样——如何检查 DOM 是否已经加载到 Javascript 中?但问题是:

  • 不使用 jQuery 等框架;
  • 在 DOM 已经加载之后,不知道您的脚本是通过静态放置的 <script>标记加载的,还是通过其他 Javascript 加载的。

这样做是否更可靠,是否具有跨浏览器兼容性?

补充: 让我澄清一下: 我正在写一个独立的。可以包含在任意网页中的 JS 文件。我想执行代码 之后的 DOM 已经加载。但我不知道 怎么做我的脚本将被包括在内。它可以通过放置 <script>标记(在这种情况下,传统的 onload或 DOM 准备解决方案将工作) ; 或者可以通过 AJAX 或其他方式加载,在 DOM 已经加载之后很久(因此前面提到的解决方案将永远不会触发)。

80203 次浏览

Here is one way by running script at the bottom of the page. In addition by using the window.onload you can wait for all images/scripts to be loaded. Or you could simply place code at the bottom not waiting for images to be loaded.

<html>
<head>
</head>
<body>
</body>
<script language="text/javascript">
window.onload = (function (oldOnLoad) {
return function () {
if (oldOnLoad) {
olOnLoad();  //fire old Onload event that was attached if any.
}
// your code to run after images/scripts are loaded
}
})(window.onload);


// your code to run after DOM is loaded
</script>
</html>

Edited: for Vilx's Comment

Many onload bindings here is an example http://jsfiddle.net/uTF2N/3/

Firefox, Opera and Webkit-based browsers have a document-level event DOMContentLoaded that you can listen for with document.addEventListener("DOMContentLoaded", fn, false).

It is more complicated in IE. What jQuery does in IE is watch onreadystatechange on the document object for a particular readystate with a backup of the document.onload event. document.onload fires later than the DOM is ready (only when all images have finished loading) so it's only used as a backstop in case the earlier events don't work for some reason.

If you spend some time Googling, you will find code to do this. I figure the most vetted code to do this is in the large frameworks like jQuery and YUI so, even if I'm not using that framework, I look in their source code for techniques.

Here's the main part of jQuery 1.6.2 source for document.ready():

bindReady: function() {
if ( readyList ) {
return;
}


readyList = jQuery._Deferred();


// Catch cases where $(document).ready() is called after the
// browser event has already occurred.
if ( document.readyState === "complete" ) {
// Handle it asynchronously to allow scripts the opportunity to delay ready
return setTimeout( jQuery.ready, 1 );
}


// Mozilla, Opera and webkit nightlies currently support this event
if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );


// A fallback to window.onload, that will always work
window.addEventListener( "load", jQuery.ready, false );


// If IE event model is used
} else if ( document.attachEvent ) {
// ensure firing before onload,
// maybe late but safe also for iframes
document.attachEvent( "onreadystatechange", DOMContentLoaded );


// A fallback to window.onload, that will always work
window.attachEvent( "onload", jQuery.ready );


// If IE and not a frame
// continually check to see if the document is ready
var toplevel = false;


try {
toplevel = window.frameElement == null;
} catch(e) {}


if ( document.documentElement.doScroll && toplevel ) {
doScrollCheck();
}
}
},

The document.readyState property can be used to check if the document is ready. From MDN:

Values

The readyState of a document can be one of following:

  • loading – The document is still loading.
  • interactive – The document has finished loading and the document has been parsed but sub-resources such as images, stylesheets and frames are still loading.
  • complete – The document and all sub-resources have finished loading. The state indicates that the load event is about to fire.

Code example:

if(document.readyState === "complete") {
// Fully loaded!
}
else if(document.readyState === "interactive") {
// DOM ready! Images, frames, and other subresources are still downloading.
}
else {
// Loading still in progress.
// To wait for it to complete, add "DOMContentLoaded" or "load" listeners.


window.addEventListener("DOMContentLoaded", () => {
// DOM ready! Images, frames, and other subresources are still downloading.
});


window.addEventListener("load", () => {
// Fully loaded!
});
}

If relying on document.readyState is ok, quick-and-dirty solution with polling:

(function() {
var state = document.readyState;
if(state === 'interactive' || state === 'complete') {
// do stuff
}
else setTimeout(arguments.callee, 100);
})();

This works for all browsers and is short and concise:

var execute = function () {
alert("executing code");
};


if ( !!(window.addEventListener) )
window.addEventListener("DOMContentLoaded", execute)
else // MSIE
window.attachEvent("onload", execute)

The DOMContentLoaded event is fired when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading.Good thing is chrome, firefox, IE9, opera and safari supports it equally

document.addEventListener("DOMContentLoaded", function(event)
{
console.log("DOM fully loaded and parsed");
}

NOTE : Internet Explorer 8 supports the readystatechange event, which can be used to detect when the DOM is ready.