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


73

问题是如此之多,无论是在网上还是在网络上-如何检查DOM是否已加载到Javascript中?但是这里有个陷阱:

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

是否可以或多或少可靠地做到这一点并且具有跨浏览器的兼容性?

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


3
document.readyState属性可以使用,尽管我不确定浏览器是否兼容...
Digital Plane

1
恐怕不是很好。:(
Vilx-


1
参见这个小实用程序:github.com/cms/domready,它大约减少了约0.5kb。
Christian C.Salvadó11年

1
@DigitalPlane-我收回了。它具有很好的浏览器支持!将其添加为答案,我会接受。
Vilx-

Answers:


84

document.readyState属性可用于检查文档是否准备就绪。从MDN:

价值观

文档的readyState可以是以下之一:

  • 加载中-文档仍在加载中。
  • 交互式的–文档已完成加载并且文档已被解析,但是子资源(例如图像,样式表和框架)仍在加载中。
  • 完成–文档和所有子资源已完成加载。状态指示加载事件即将触发。

代码示例:

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!
    });
}

4
请紧记addEventListener()IE9所添加的功能,该功能不适用于Windows XP
Christoph

1
当然。这与DOMReady事件模拟的其他解决方案一起使用。
Vilx- 2011年

7
首先,这不是跨浏览器有效的。第二,这也等待图像加载。这就像window.onload。
Brian Sweat 2013年

5
您不应该听一个名为load而不是的事件onload吗?
natevw 2014年

2
[Esoterica警告] *我认为使用document.readyState ==“ complete”而不是document.readyState ===“ complete” *根据您的代码将要执行的操作,等待更合适直到所有图像都加载完毕*浏览器制造商如此毫不妥协地不称职,这是否令人沮丧?关于JavaScript设计的所有事情都是绝对错误的。
辩论者2016年

10

Firefox,Opera和基于Webkit的浏览器都有一个文档级事件DOMContentLoaded,您可以使用监听document.addEventListener("DOMContentLoaded", fn, false)

在IE中更为复杂。jQuery在IE中的作用是监视onreadystatechange文档对象的特定就绪状态,并备份document.onload事件。document.onload在DOM准备就绪之后才触发(仅当所有图像均已完成加载时),因此它仅用作备用,以防早期事件由于某种原因而无法正常工作。

如果您花一些时间在Google上搜索,则会发现执行此操作的代码。我认为最适合此操作的代码是在jQuery和YUI之类的大型框架中,因此,即使我不使用该框架,我也会在其源代码中查找技术。

这是jQuery 1.6.2源代码的主要部分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();
        }
    }
},

1
再一次-如果在DOM已经加载后附加事件处理程序,则将无法使用。
Vilx-

4
查看我包含的jQuery源。这就是为什么他们以开头的行,if ( document.readyState === "complete" ) {因此他们将处理文档已准备就绪的情况。如果要构建自己的微型框架来执行此操作,则必须自己构建此类功能。
jfriend00

9

如果document.readyState可以,可以通过轮询快速解决问题:

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

document.readyState是我的问题的答案。正如我多次指出的那样,附加到“ DOMReady”类事件不是问题。问题是readyState == complete时,因此DOMReady事件将永远不会触发。
Vilx- 2011年

@ Vilx-:我的意思是,如果您仍然依赖document.readyState(即,您不希望支持传统的非IE浏览器),则根本不需要任何特定于浏览器的代码(DOMContentLoadedvs. onloadvs. onreadystatechangeaddEventListenervs attachEvent) -上述方案作品无处不在
克里斯托夫

据我所知,我唯一不支持的浏览器是3.6以下的FireFox。而且,说实话,这是一个极端的情况(大多数脚本将以传统方式包括在内),因此,如果我因某种非常罕见的组合而错过它,那将不是什么大问题。:P
Vilx- 2011年

8

这适用于所有浏览器,且简洁明了:

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

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

4

DOMContentLoaded初始HTML文件已完全加载并解析后,无需等待样式表,图像和子帧完成加载,就会触发此事件。Chrome,firefox,IE9,opera和safari同样支持该事件

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

注意:Internet Explorer 8支持readystatechange事件,该事件可用于检测DOM准备就绪的时间。


2

这是在页面底部运行脚本的一种方法。另外,通过使用window.onload,您可以等待所有图像/脚本被加载。或者,您可以简单地将代码放在底部,而无需等待图像加载。

<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>

编辑:针对Vilx的评论

这里有许多onload绑定,例如http://jsfiddle.net/uTF2N/3/


+1。您可能想要添加一个解释,以说明如何在以后搜索并发现经验不足的人们中使用。
肯·怀特

1
我认为您违反了:“在不知道您的脚本是通过DOM加载之后还是通过静态放置的<script>标记或其他Java脚本加载的”。
维·莫里森

对不起,我没有说过我正在谈论一个独立的脚本。我澄清了
Vilx-

@李维·莫里森 window.onload在所有图像/脚本加载后运行。
约翰·哈索克

就我而言,我什至都不在乎,但即使如此,也有很多可用的DOM就绪脚本,因此无需担心。主要问题是我不知道onload事件是否早已触发,因此将另一个处理程序附加到该事件将无效。
Vilx-
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.