DOMContentLoaded 事件中的代码不起作用

IT技术 javascript babeljs addeventlistener domcontentloaded
2021-03-21 16:46:44

我用过了

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

6个回答

这很可能是因为此时该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() {}
嗯,我觉得要走的标准方式就是确保script在身体的末端,不是做文章,用DOMContentLoaded只有在作者无法控制脚本标签的位置时才会使用的代码需要这个(有趣的是,Babel Standalone)。
2021-04-26 16:46:44
不要检查document.readyState === 'complete'检查 for document.readyState !== 'loading',因为听DOMContentLoadedifdocument.readyState是“交互式的”是没有用的。测试您的错误并修复代码。
2021-04-27 16:46:44
哈,是的,我想这几乎是当今使用 vanilla JS 的标准方法。
2021-05-03 16:46:44
TJ是这样吗?如果您的脚本块位于正文的末尾,它永远不会与 DOMContentLoaded 监视的“其他内容”发生冲突?
2021-05-05 16:46:44
不错的 - OP问我如何处理它是否已经运行以激励我添加它,然后我看到你已经......
2021-05-09 16:46:44

该事件在代码挂钩它时已经触发。该方法巴贝尔独立的工作原理是通过响应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 Standalone 会等你。

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


在您问过的评论中:

但是我在开发中使用 Babel Standalone,但是我会在投入生产时对其进行预编译。当我投入生产时,我应该重新添加它吗?

只需确保您的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"在文档加载时返回"interactive"一旦完成解析但仍在加载子资源,以及"complete"一旦加载。

但是我在开发中使用 Babel Standalone,但是我会在投入生产时对其进行预编译。当我投入生产时,我应该重新添加它吗?
2021-05-07 16:46:44
@Ruslan:谢谢。我被规范误导,说“每个文档都有当前的文档准备情况。创建 Document 对象时,如果文档与 HTML 解析器(XML 解析器)相关联,则它必须将其当前文档准备状态设置为字符串“正在加载” , 或 XSLT 处理器,否则为字符串“完成”。页面加载期间的各种算法都会影响此值。设置该值后,用户代理必须在 Document 对象上触发一个名为 readystatechange 的简单事件。但就之上,很明显有一个中间"interactive"状态!:-)
2021-05-09 16:46:44
@Jamgreen:我在上面的答案中添加了对该评论的回复。
2021-05-15 16:46:44

感谢 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');
}

另一种选择是使用该readystatechange事件。readystatechange当 的readyState属性document发生变化时触发事件所述readyState属性可以是以下三个值之一:'loading''interactive',或'complete'使用的另一种DOMContentLoaded事件是看为readyState等于'interactive'所述的内部documentreadystatechange情况下,如在下面的代码段。

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

虽然,就您而言,document'sreadyState似乎已经达到'complete'. 在这种情况下,你可以简单地换'interactive''complete'在上面的代码片段。这在技术上等于load事件而不是DOMContentLoaded事件。

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

我只是遇到了 DOMContentLoaded 不起作用的问题,所以根据您的回答和 readystate = complete 检查它工作正常 - 非常感谢!
2021-05-13 16:46:44

我在 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/