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

Posted

技术标签:

【中文标题】如何在没有框架的情况下检查 DOM 是不是准备就绪?【英文标题】:How to check if DOM is ready without a framework?如何在没有框架的情况下检查 DOM 是否准备就绪? 【发布时间】:2011-12-27 09:15:45 【问题描述】:

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

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

这可以或多或少可靠地完成并具有跨浏览器兼容性吗?

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

【问题讨论】:

可以使用document.readyState属性,虽然我不确定浏览器的兼容性... 恐怕不太好。 :( Haveyoutriedtosearch? 查看这个小实用程序:github.com/cms/domready 大约缩小了约 0.5kb。 @DigitalPlane - 我收回了。它具有该死的良好浏览器支持!将其添加为答案,我会接受。 【参考方案1】:

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

价值观

文档的就绪状态可以是以下之一:

loading – 文档仍在加载中。 interactive – 文档已完成加载,文档已被解析,但图像、样式表和框架等子资源仍在加载中。 complete – 文档和所有子资源已完成加载。该状态表明load 事件即将触发。

代码示例:

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

【讨论】:

请记住 addEventListener() 是随 IE9 添加的,不适用于 Windows XP 当然。这与 DOMReady 事件模拟的其他解决方案一起使用。 首先,这不是跨浏览器有效的。二,这也等待图像加载。这就像 window.onload. 你不应该听一个名为load而不是onload的事件吗? [Esoterica 警告] * 我认为使用 document.readyState == "complete" 而不是 document.readyState === "complete" * 取决于您的代码将执行的操作,等到所有图片都加载完可能更合适 *浏览器制造商都如此不妥协地无能,这不是令人沮丧吗?关于 JavaScript 设计的一切都是绝对错误的。【参考方案2】:

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

在 IE 中比较复杂。 jQuery 在 IE 中所做的是在文档对象上监视 onreadystatechange 以获取特定的就绪状态,并备份 document.onload 事件。 document.onload 在 DOM 准备就绪后触发(仅在所有图像完成加载时),因此它仅用作在早期事件由于某种原因不起作用的情况下的支持。

如果您花一些时间谷歌搜索,您会找到执行此操作的代码。我认为最受审查的代码是在 jQuery 和 YUI 等大型框架中,因此,即使我没有使用该框架,我也会查看它们的源代码以获取技术。

这是document.ready()的jQuery 1.6.2源代码的主要部分:

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();
        
    
,

【讨论】:

再一次 - 如果我在 DOM 已经加载后附加我的事件处理程序,这将不起作用。 查看我包含的 jQuery 源代码。这就是为什么他们有以if ( document.readyState === "complete" ) 开头的行,因此他们将处理文档已经准备好的情况。如果您正在构建自己的迷你框架来执行此操作,则必须自己构建此类功能。【参考方案3】:

如果依赖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-:我的意思是,如果您仍然依赖document.readyState(即您不想支持旧版非 IE 浏览器),则不需要任何特定于浏览器的浏览器完全没有代码(DOMContentLoaded vs. onload vs. onreadystatechangeaddEventListener vs attachEvent) - 上述解决方案无处不在 据我所知,我唯一不支持的浏览器是 3.6 以下的 FireFox。而且,老实说,这是一个边缘案例(大部分脚本将包含在传统方式中),所以如果我因为一些非常罕见的组合而错过它,那也没什么大不了的。 :P【参考方案4】:

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

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

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

【讨论】:

【参考方案5】:

DOMContentLoaded 事件在初始 html 文档完全加载和解析后触发,无需等待样式表、图像和子框架完成加载。好在 chrome、firefox、IE9、opera 和 safari 都支持它

document.addEventListener("DOMContentLoaded", function(event) 

    console.log("DOM fully loaded and parsed");

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

【讨论】:

【参考方案6】:

这是在页面底部运行脚本的一种方法。此外,通过使用 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。不过,您可能想添加一个解释,说明这是如何工作的,以便人们稍后搜索并发现可能没有很多经验的人。 我认为您违反了:“不知道您的脚本是通过静态放置的 对不起,我没有说我在谈论独立脚本。我澄清了。 @Levi Morrison。 window.onload 在加载所有图像/脚本后运行。 就我而言,我什至不会太在意,但即便如此,仍有大量可用的 DOM 就绪脚本,因此无需担心。主要问题是我不知道是否可能早就触发了 onload 事件,因此附加另一个处理程序将无效。

以上是关于如何在没有框架的情况下检查 DOM 是不是准备就绪?的主要内容,如果未能解决你的问题,请参考以下文章

硬件重置后如何检查英特尔实感设备是不是准备就绪?

如何在没有 API 8 中引入的 onLoadCompleteListener 的情况下检查 SoundPool 是不是准备好播放?

检查使用O_NONBLOCK打开的文件描述符是否准备就绪

在 node.js 中检查存储桶是不是准备就绪的最佳方法

检查是不是在没有 DOM 对象的情况下单击了“a”链接

如何在不使用 jQuery(替代方式)的情况下知道页面何时准备就绪? [复制]