51

我用过

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
</head>
<body>
  <button type="button" id="button">Click</button>
  <pre id="output">Not Loading...</pre>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.17.0/babel.min.js"></script>
  <script type="text/babel">
    document.addEventListener('DOMContentLoaded', function () {
      const button = document.getElementById('button');
      const output = document.getElementById('output');

      output.textContent = 'Loading...';

      addEventListener('click', function () {
        output.textContent = 'Done';
      });
     });
  </script>
</body>
</html>

但似乎里面的代码document.addEventListener('DOMContentLoaded', function () {});没有加载。

如果我从我的代码中删除它,它会突然起作用。

我在这里做了一个 JS Bin

4

9 回答 9

117

这很可能是因为此时该DOMContentLoaded事件已被触发。一般来说,最佳实践是检查document.readyState以确定您是否需要监听该事件。

if( document.readyState !== 'loading' ) {
    console.log( 'document is already ready, just execute code here' );
    myInitCode();
} else {
    document.addEventListener('DOMContentLoaded', function () {
        console.log( 'document was not ready, place code here' );
        myInitCode();
    });
}

function myInitCode() {}
于 2016-10-12T08:17:56.400 回答
15

该事件在代码挂钩时已经触发。Babel 独立工作的方式是DOMContentLoaded通过查找和执行type="text/babel"页面上的所有脚本来响应。您可以在index.js文件中看到这一点:

// Listen for load event if we're in a browser and then kick off finding and
// running of scripts with "text/babel" type.
const transformScriptTags = () => runScripts(transform);
if (typeof window !== 'undefined' && window && window.addEventListener) {
  window.addEventListener('DOMContentLoaded', transformScriptTags, false);
}

只需直接运行代码,无需等待事件,因为您知道 Babel 独立会等待它。

另请注意,如果您将脚本放在正文的末尾,就在结束标记之前,即使您不使用 Babel </body>,也无需等待。DOMContentLoaded脚本上面定义的所有元素都将存在并且可用于您的脚本。


在您问过的评论中:

但是我在开发中使用的是独立的 Babel,但是我会在投入生产时预编译它。我应该在投入生产时重新添加它吗?

只需确保您的标签位于如上所述script的末尾,并且不需要使用该事件。body

如果无论如何使用它对您很重要,您可以通过检查来检查事件是否已经运行document.readyState(点击链接后,向上滚动一点):

function onReady() {
    // ...your code here...
}
if (document.readyState !== "loading") {
    onReady(); // Or setTimeout(onReady, 0); if you want it consistently async
} else {
    document.addEventListener("DOMContentLoaded", onReady);
}

document.readyState经历了这些阶段(从上面的链接稍微向上滚动):

"loading"在 Document 加载时返回,"interactive"一旦完成解析但仍在加载子资源,以及"complete"一旦加载。

于 2016-10-12T08:18:41.950 回答
2

感谢 Ruslan & 这里是完整的代码片段,使用DOMContentLoaded后可以方便地分离处理程序。

'use strict';
var dclhandler = false;
if (document.readyState !== 'loading') {
    start();
} else {
    dclhandler = true;
    document.addEventListener('DOMContentLoaded', start);
}
function start() {
    if (dclhandler) { document.removeEventListener('DOMContentLoaded', start); }
    console.log('Start the site`s JS activities');
}
于 2017-10-08T06:34:06.793 回答
2

另一种选择是使用readystatechange事件。当 的属性发生变化时触发该readystatechange事件。该属性可以是以下三个值之一:、或。使用事件的另一种方法是在'事件中查找等于,如下面的代码片段所示。readyStatedocumentreadyState'loading''interactive''complete'DOMContentLoadedreadyState'interactive'documentreadystatechange

document.onreadystatechange = function () {
  if (document.readyState === 'interactive') {
    // Execute code here
  }
}

尽管在您的情况下,document'sreadyState似乎已经达到'complete'. 'interactive'在这种情况下,您可以简单地在上面的代码段中进行交换'complete'。这在技术上等于load事件而不是DOMContentLoaded事件。

阅读 MDN 上的更多信息, Document.readyState 文档:readystatechange 事件

于 2020-01-09T12:44:54.270 回答
1

当我在 Cloudflare 中同时启用 HTML Auto Minify 和 Rocket Loader 时,我也遇到了同样的问题。结论是,当这些功能同时处理时,缺少 DOMContentLoaded 事件。

您可以在 HTML 文件脚本块中的所有 DOMContentLoaded 事件侦听器之前添加以下代码来解决此问题。

var inCloudFlare = true;
window.addEventListener("DOMContentLoaded", function () {
    inCloudFlare = false;
});
if (document.readyState === "loading") {
    window.addEventListener("load", function () {
        if (inCloudFlare) window.dispatchEvent(new Event("DOMContentLoaded"));
    });
}

解释请到我的博客。

https://hollowmansblog.wordpress.com/2021/10/18/solution-to-missing-domcontentloaded-event-when-enabling-both-html-auto-minify-and-rocket-loader-in-cloudflare/

于 2021-10-17T16:43:01.270 回答
0

https://learnwithparam.com/blog/vanilla-js-equivalent-of-jquery-ready/

function ready(callbackFunc) {
  if (document.readyState !== 'loading') {
    // Document is already ready, call the callback directly
    callbackFunc();
  } else if (document.addEventListener) {
    // All modern browsers to register DOMContentLoaded
    document.addEventListener('DOMContentLoaded', callbackFunc);
  } else {
    // Old IE browsers
    document.attachEvent('onreadystatechange', function() {
      if (document.readyState === 'complete') {
        callbackFunc();
      }
    });
  }
}

ready(function() {
  // your code here
});

于 2020-05-07T11:32:16.320 回答
0

我的清洁方法...

if (document.readyState !== 'loading') init()
else document.addEventListener('DOMContentLoaded', init);

function init() {
    console.log("Do it !");
    ...
}
于 2020-06-06T19:43:01.130 回答
0

我会用document.addEventListener("DOMContentLoaded", () => {/*yourcode*/});

于 2020-05-06T17:24:55.207 回答
-1

我的实时服务器遇到了这个问题。我的实时服务器在cloudflare上运行,带有一些缓存和火箭加载 js。我认为这是导致意外行为的原因。使用 DOMContentLoaded 时,该代码在本地服务器上运行良好,但不是在现场运行。

如果可以使用 jQuery,请切换到

jQuery(document).ready(function() {
//code...
})

按预期工作。

于 2021-04-28T14:21:43.807 回答