web-dev-qa-db-ja.com

DOMContentLoadedイベント内のコードが機能しない

利用した

_<!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 here を作成しました。

15
Jamgreen

これはおそらく、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() {}
45
jAndy

イベントは、コードがフックするまでにalready発生します。 Babel standalone が機能する方法は、ページ上のtype="text/babel"スクリプトをすべて見つけて実行することにより、DOMContentLoadedに応答することです。これは 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スタンドアロンがそれを待っていることを知っているので、イベントを待たずに直接コードを実行するだけです。

また、スクリプトを本文の最後の</body>タグの直前に配置すると、Babelを使用しなくても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"、解析が終了してもサブリソースの読み込みが完了すると"interactive"、読み込みが完了すると"complete"を返します。

12
T.J. Crowder

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');
}
0
bob-12345