DOMContentLoaded事件中的代码无法正常工作

Jam*_*een 18 javascript addeventlistener domcontentloaded babeljs

我用过

<!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>
Run Code Online (Sandbox Code Playgroud)

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

如果我从我的代码中删除它,它突然工作.

在这里做了一个JS Bin.

jAn*_*ndy 53

这很可能是因为此时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() {}
Run Code Online (Sandbox Code Playgroud)

  • 不要检查`document.readyState ==='complete'`!检查`document.readyState!=='loading',因为如果`document.readyState`是'interactive',那么侦听`DOMContentLoaded`是没用的.测试您的错误并修复代码. (11认同)

T.J*_*der 13

在代码挂钩时,事件已经触发了.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);
}
Run Code Online (Sandbox Code Playgroud)

只需直接运行代码,无需等待事件,因为您知道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);
}
Run Code Online (Sandbox Code Playgroud)

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

"loading"在文档加载时返回,"interactive"一旦完成解析但仍然加载子资源,并且"complete"一旦加载就返回.