【问题标题】:Javascript domready?Javascript 准备好了吗?
【发布时间】:2023-03-30 05:38:01
【问题描述】:

我知道我可以使用原型或 jQuery 等不同的框架将函数附加到 window.onload,但这不是我想要的。

我需要像 .readyState 这样的东西,这样我就可以做这样的事情:

if(document.isReady){
  var id = document.getElem ...
}

除了使用框架的功能之外,还有其他方法吗?

【问题讨论】:

  • 可靠地跨浏览器检测 DOM 就绪并非易事。您为什么不想使用经过验证的框架之一?
  • 我建议看一下 domassistant - 它是一个非常轻量级的库。或者,检查 d-lite 以获得额外的轻量级功能集。
  • 我被要求不要,基本上。
  • 查看my answer 的类似问题以获得跨浏览器 DOMReady 对象的链接。
  • 您可能需要重新考虑正确答案。

标签: javascript dom-events


【解决方案1】:

编辑:随着 2018 年的到来,我认为收听 DOMContentLoaded 事件是安全的。

function fireOnReady() { /* ... */ }
if (document.readyState === 'complete') {
    fireOnReady();
} else {
    document.addEventListener("DOMContentLoaded", fireOnReady);
}

请注意,该事件只会在您的页面加载时触发一次!如果您必须支持非常旧的浏览器,请查看我在下面整理的超轻量级脚本。



仅供历史参考:



jQuery 有一个名为 isReady 的未记录属性,它在内部用于确定是否触发了 DOM 就绪事件:

if($.isReady) {
    // DOM is ready
} else {
    // DOM is not yet ready
}

我从 1.5.2 开始,一直到 1.3.2,财产就在那里。虽然没有记录,但我会说您可以在 jQuery 的未来版本中依赖此属性。 编辑:一年后 - v1.7.2,他们仍然使用$.isReady - 仍然没有记录,所以请自担风险使用。升级时要小心。

编辑: v1.9,他们仍然使用$.isReady - 仍然没有记录

编辑: v2.0 进行了所有“重大”更改,仍然使用 $.isReady - 仍然没有记录

编辑: v3.x 仍然使用 $.isReady - 仍然没有记录

编辑:正如一些人所指出的,以上内容并没有真正回答这个问题。所以我刚刚创建了一个mini DOM ready snippet,它的灵感来自达斯汀迪亚兹的even smaller DOM ready snippet。 Dustin 创建了一种简洁的方法来检查文档的 readyState,类似于以下内容:

if( !/in/.test(document.readyState) ) {
    // document is ready
} else {
    // document is NOT ready
}

之所以可行是因为浏览器有 3 种加载状态:“正在加载”、“交互”和“完成”(旧的 WebKit 也使用“加载”,但您不必担心更多)。您会注意到“加载”和“交互”都包含文本“in”......所以如果在document.readyState 中找到字符串“in”,那么我们知道我们还没有准备好。

【讨论】:

  • 不知道为什么投反对票。我解释说这是无证的。在 jQuery 的未来版本中调试这个问题将非常简单,它是那些自描述变量之一,永远不会通过“有一个更好的名字”测试,因此可能永远不会被重命名。无论如何...我希望人们能解释反对票。
  • 这不能回答问题(OP 不想使用框架)。但是,它确实为标记为“完全重复”的问题提供了一个很好的答案(来自我的 +1)。 stackoverflow.com/questions/8373910/…
  • Upvoted- 不回答这个问题,但回答了很多人在这里结束的问题。
  • 要求是在不使用框架的情况下准备好 dom。您的示例解决了问题,但使用了框架。这应该是另一个问题的一部分,询问如何使用 JQuery 准备好 dom,但不应该是当前问题的解决方案。不要为解决另一个问题投票。仅在解决当前问题时投赞成票。
  • @et al - 这是我对 S.O. 的最早回答之一。我的方式并不聪明。感谢那些指出我短视的人,我早就更新了我的答案以包含一个无框架的解决方案。
【解决方案2】:
document.addEventListener("DOMContentLoaded", function(e){
    console.log("dom ready");//output to web browser console
});

这个不需要 JQuery。无需在 DOMContentLoaded 上传递第三个参数,因为此事件没有父级来遍历该事件。也没有必要完全看中其他人在说什么。这将告诉您 DOM 何时完全加载并准备好使用。当我注意到 DOM 助手库时,我大笑。该库是绝对没用的。

DOMContentLoaded 事件在文档完全加载和解析后触发,无需等待样式表、图像和子框架完成加载

addEventListener() 是一个很棒的函数,用于检查任何事件,包括 DOM 就绪状态。使用“DOMContentLoaded”时,不需要addEventListener() 中的第三个参数,因为此触发器也没有父项来传递事件。在我上面的例子中,你会注意到第二个参数是一个匿名函数。您还可以将函数的名称传递给第二个参数。

document.addEventListener([(string)event trigger], [function],[(boolean)traverse DOM tree]);

在 JQuery 上使用它的另一个好处是当您更新 JQuery 时它不会中断。

【讨论】:

    【解决方案3】:

    自提出此问题以来的 5 年中,DOMContentLoaded 已成为普遍支持的事件,您可以直接使用它。

    document.addEventListener('DOMContentLoaded', function() {
        //.. do stuff ..
    }, false);
    

    【讨论】:

    • 我正准备自己发表关于 DOMContentLoaded 的评论。由于这里没有任何不同意见,我认为这是正确的方法吗?
    • 现代浏览器都支持这个caniuse.com/#search=DOMContentLoaded
    • 为什么你在人们已经对 addEventListener() 发表评论一年后才发布这个。您还没有添加任何其他答案之前已经完成的内容。
    • 好吧,抱歉,Patrick,我知道我似乎故意以与您相同的方式重新回答了这个问题,以窃取您的互联网积分,但老实说,我没有看到您的答案。我当时滚动浏览并认为这很有趣,没有人指出这不再是需要 3rd 方代码的问题。我认为,这仍然是我的回答中人们赞成的部分——这现在得到了普遍支持。
    【解决方案4】:

    如果您想要只做特定事情的更小的库,您可以使用microjs 中的库。对于手头的问题,可以使用 DOMStatic libs ready 方法。

    【讨论】:

      【解决方案5】:

      我已经更新了 DOMAssistant library 的代码,它对我来说很好用

      var domReady = (function (){
        var arrDomReadyCallBacks = [] ;
        function excuteDomReadyCallBacks(){
             for (var i=0; i < arrDomReadyCallBacks.length; i++) {
               arrDomReadyCallBacks[i]();
             }
             arrDomReadyCallBacks = [] ;
        }
      
        return function (callback){
          arrDomReadyCallBacks.push(callback);
           /* Mozilla, Chrome, Opera */
            if (document.addEventListener ) {
                document.addEventListener('DOMContentLoaded', excuteDomReadyCallBacks, false);
            }
          /* Safari, iCab, Konqueror */
          if (/KHTML|WebKit|iCab/i.test(navigator.userAgent)) {
              browserTypeSet = true ;
              var DOMLoadTimer = setInterval(function () {
                  if (/loaded|complete/i.test(document.readyState)) {
                      //callback();
                      excuteDomReadyCallBacks();
                      clearInterval(DOMLoadTimer);
                  }
              }, 10);
          }
          /* Other web browsers */
      
          window.onload = excuteDomReadyCallBacks;
      }
      })()
      

      【讨论】:

      • 为什么投反对票?代码用 ie 8 、firefox 和 chrome 测试。
      • 您的示例是 Rube Goldberg 机器。记住在编程 KISS 方法时。有一种简单的解决方案可以解决问题,无需额外处理。请添加更多文档,说明为什么需要您的解决方案而不是更简单的单行解决方案。没有文档的代码 sn-ps 没有得到很多支持。
      【解决方案6】:

      试试这个:
      链接:onDomReady at GitHub 或以下来源:

      if(document.ondomready == undefined) {
          document.ondomready = {};
          document.ondomready = null;
      } else {
          document.ondomready=document.ondomready;
      }
      var oldonload=document.onload;
      var isLaunched = 0;
      document.onload = function() {  
          if(oldonload !== null) {
              oldonload.call();
          }
      };
      document.addEventListener("DOMContentLoaded", function onDom(evt) {
          var olddomready = document.ondomready;
          if(olddomready !== null) {
              if(isLaunched == 0) {
                  olddomready.call(evt);
                  isLaunched == 1;
                  //We now launched the mapped DOMContentLoaded Event
              } else {
                  //We already launched DOMContentLoaded Event
              }
          }
      }, false);
      

      我已经在 Opera 11.x/12.x 上对此进行了测试。尚未在其他人身上进行测试。让我知道他们是否这样做。

      注意:我还没有上传存储库,但我会尽快在我的空闲时间。

      【讨论】:

      • "DOMContentLoaded" 在 DOM 完全加载和解析时触发一次。您添加的所有额外内容都无济于事。
      【解决方案7】:

      看看这个来自微软的演示。 -> http://ie.microsoft.com/testdrive/HTML5/DOMContentLoaded/Default.html 这里是允许你在 DOM 上运行 JS 的代码要点...

      (function () {
          function load2(){
              // put whatever you need to load on DOM ready in here
              document.getElementById("but3").addEventListener("click", doMore, false);
          }
          if (window.addEventListener) {
              window.addEventListener('DOMContentLoaded', load2, false);
          } else {
              window.attachEvent('onload', load2);
          }
      } ());
      

      这里是演示的一些 javascript 源代码。 http://ie.microsoft.com/testdrive/Includes/Script/ReturnAndShareControls.js

      效果很好。不错!!...在谷歌浏览器和 IE 9 上。

      【讨论】:

      • 我认为这应该是document.addEventListener(... 而不是window
      • @banderson623 抱歉,我已经很久没有使用帖子中的代码了,无法很好地回忆起它。也许浏览器更新已针对您建议的更改进行。
      • 你不需要addEventListener('DOMContentLoaded', load2, false)末尾的false DOMContentLoaded没有父项可以遍历。
      【解决方案8】:

      jQuery 不使用window.onload

      $(document).ready() 等到 DOM 加载完毕并且可以被遍历(到那时可能会或可能不会加载其余内容)。

      如果你调出 jQuery 的源代码并整理混乱,你会发现工作是由 bindReady() 方法完成的,该方法针对不同的浏览器有几种不同的实现,只有当所有这些实现都失败时,它才会失败重新监听窗口的加载事件。

      【讨论】:

      • @PatrickW.McMahon - 我没有建议在我的回答中使用 jQuery。如果你仔细阅读,我告诉 OP 阅读 jQuery 的源代码,看看他们是如何进行现成检测的,以便他可以模仿它。
      • 当您可以将 jQuery 代码链接到 w3schools 文档以获取 DOM 状态时,为什么还要告诉他们深入研究 jQuery 代码?只需花费更少的时间,也无需深入研究数千行 JQuery 和跟踪 JQuery 标志和触发器,只需发现它们将 w3school 演示包装到 JQuery 函数中。简单的解决方案通常是最好的解决方案。程序员的时间很宝贵。选择最有效的解决方案。当他深入研究 JQuery 框架时,他还不如只使用 JQuery。
      • @PatrickW.McMahon - 无需查看数千行。我在我的回答中告诉了 OP 究竟要查看哪种方法。 W3Schools 不会向 OP 展示在每个浏览器中实现相同功能的最佳方式。如果你想成为一个更好的开发者,你可以从好的代码中学习。 W3Schools 肯定没有好的代码。
      • @Justin Niessner - W3School 是网络的管理机构。如果您认为他们没有按照他们制定的标准提供高质量的代码,那么我们手头就有更大的问题。运行 W3School 的成员与致力于新 HTML5 标准的人相同。
      • @PatrickW.McMahon - W3School 肯定不是网络的管理机构。那将是 W3C(万维网联盟)w3.org W3Schools 已经变得比以前更好了,但仍然存在问题。查看w3fools.com 了解更多信息。
      【解决方案9】:

      虽然我通常主张在必要时避免使用框架,但我想说在这种情况下使用框架是完全可以的。这是 jQuery:

      $(function () {
          // do stuff after DOM has loaded
      });
      

      请注意,它与window.onload 事件不同,因为onload 在其他资源(图像等)加载后首先执行。我在示例中使用的代码将在 DOM 完成加载后执行,即,当完整的 HTML 结构可用时(不一定当图像、CSS 等可用时)。

      如果你想要一个可检查的变量,你可以在 ready-function 中设置一个:

      var documentIsReady = false;
      $(function () { documentIsReady = true; });
      

      当然,如果您只想检查 DOM 就绪,您可以找到比 jQuery 更多的轻量级库。但是在不同浏览器的行为非常不同的情况下使用库(这是一种情况。)

      使用DOMAssistant library 中的一些代码,制作您自己的“DOM 就绪”函数应该不会太难:

      var domLoaded = function (callback) {
          /* Internet Explorer */
          /*@cc_on
          @if (@_win32 || @_win64)
              document.write('<script id="ieScriptLoad" defer src="//:"><\/script>');
              document.getElementById('ieScriptLoad').onreadystatechange = function() {
                  if (this.readyState == 'complete') {
                      callback();
                  }
              };
          @end @*/
          /* Mozilla, Chrome, Opera */
          if (document.addEventListener) {
              document.addEventListener('DOMContentLoaded', callback, false);
          }
          /* Safari, iCab, Konqueror */
          if (/KHTML|WebKit|iCab/i.test(navigator.userAgent)) {
              var DOMLoadTimer = setInterval(function () {
                  if (/loaded|complete/i.test(document.readyState)) {
                      callback();
                      clearInterval(DOMLoadTimer);
                  }
              }, 10);
          }
          /* Other web browsers */
          window.onload = callback;
      };
      

      未经测试,但它应该可以工作。我从 DOMAssistant 简化了它,因为 DOMAssistant 允许多个回调,并且检查以确保您不能两次添加相同的函数等。

      【讨论】:

      • 这是我唯一需要的框架,它必须提供的所有其他东西,我不需要,所以如果可能的话,我宁愿在这种情况下不使用框架,否则我会使用 jquery
      • 好的,我添加了一些来自 DOMAssistant 的简化代码,你可以试试。根据他们的网站,它应该适用于所有主要浏览器。 domassistant.com/documentation/DOMAssistantLoad-module.php
      • 我的代码最多会调用callback 两次(因为window.onload 应该在所有浏览器中执行。)处理事件时,检查callback 是否已经被调用,如果有则返回(这是 DOMAssistant 所做的,但我删除了那部分。)
      • 在不考虑实际值的情况下更改window.onload 的值可能会在其他脚本的代码中产生意外行为。我们也不能调用domLoaded 两次,因为只会使用最后一个。
      • 这段代码对我有用!除非我必须使用 else if 否则 firefox 会触发两次。
      【解决方案10】:

      这实际上是大多数人使用 jQuery 等框架的最大原因之一,因为解决方案在浏览器之间并不一致。

      【讨论】:

      • 我知道,我自己也是 jquery 的重度用户,但在这种情况下我不想依赖框架,我被要求避免使用它。
      • 我建议您查看 jQuery 的源代码并将您想要的代码移植到您的项目中。
      • 准备好 DOM 是一行代码document.addEventListener("DOMContentLoaded", function(e){/*dom ready do something*/}); 怎么这么难,你需要使用框架来准备好 dom?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-14
      • 2015-11-08
      • 2017-12-23
      • 2016-07-17
      • 2017-01-07
      • 2011-10-21
      相关资源
      最近更新 更多