職案人

求職・歴史・仏教などについて掲載するつもりだが、自分の思いつきが多いブログだよ。適当に付き合って下さい。

イベントハンドラの記述位置

2024年08月26日 | JavaScript

イベントハンドラを登録するコードの記述位置に関する注意と対処方法

【開発環境】
OS:Win11(64ビット)
VSCode1.72.2、
クロム

【コード順序に依るエラー】
例文

<script>要素と<input>要素の順序を逆さにすると、エラー

>> TypeError: Cannot read property 'addEventListener' of null
理由は、
HTML ページはファイルのダウンロードが終わったあと、 HTML ページに記述されている内容をページの先頭から順にパース(解析)して DOM ツリーを構築し始め、<script>タグを見つける度、パースを中断してjavascriptのコードを実行し始める。

最初に getElementById メソッドを使って id 属性が 'xxx' の要素ノードを取得しようとしますが、この要素は <script> よりも後に記述されているため、まだパースが行われておらず見つけることができません。その結果、変数 button には null が格納されます。

次の文で addEventListener メソッドを実行しようとしますが、ターゲットである変数 button には null が格納されているため、エラーが発生する。

これは外部のファイルに JavaScript のコードを記述し、そのファイルを読み込んでいる場合でも同じである。

----対策方法---

JavaScriptのコードはHTMLページの末尾に記述する】-----------
一つ目の方法はこれまでのサンプルでも行ってきたようにターゲットとなる要素を HTML ページで先に記述し、それよりもあとで <script> を記述することです。

サンプル

JS

動作結果--ボタンをクリックすると、アラームが表示する

DOMContentLoadedイベントを利用する】--------------
ターゲットなる要素よりも前に <script> タグを記述したい場合はContentLoadedイベントを利用する。つまり、<head> タグ内に <script>タグを記述することが出来る。

これは、 JavaScript のコードが先に書いたとしても、HTMLの要素の解析が終わって DOM ツリーが完成すると、document.DOMContentLoaded というイベントが発生します。この時、addEventListenerイベントリスナーは JavaScriptのコードで書かれたイベントハンドラの実行をDOM ツリーが完成するまで、停止させるからである。

DOMContentLoaded イベントが発生すると、イベントリスナーとして登録したコードが実行され、ターゲットの要素の取得と click イベントへのイベントリスナーの登録が実行されます。
サンプルコード
「DOMContentLoaded.html」ファイルを書く

「main2.js」ファイルを書く

ブラウザを立ち上げ、ボタンをクリックする


以上
【loadイベントを利用する】-------
DOMContentLoaded イベントは document オブジェクトで発生します。 document オブジェクトには ondomcontentloaded プロパティが存在しないため、プロパティを使ったイベントハンドラの設定を行う方法は使用できません。
※ondomcontentloaded を下記のように使うことが出来ます。しかし、一般的にサポートされていないプロパティであり、実際には存在しないか、あるいは期待通りに機能しない可能性があり、今はDOMContentLoadedの方が推奨されている。
document.ondomcontentloaded = function(event) {
  console.log('DOM が完全に読み込まれました');
  // ここに DOM の操作を記述
};
そこで、代わりに window オブジェクトで発生する load イベントを利用することにする。
つまり、DOM ツリーの構築が完了すると DOMContentLoaded イベントが発生しますが、そのあとで画像やスタイルシートなどすべてのリソースの読み込みが完了すると load イベントが発生します。これを利用して、ヘッダー部分に JavaScript のコードを書いてみる。

load イベントが発生すると、イベントハンドラとして登録したコードが実行され、ターゲットの要素の取得と click イベントへのイベントハンドラの登録が実行されます。
サンプル
「onload.html」ファイルを書く

外部のjsファイルを書く

ブラウザを立ち上げ、ボタンをクリックする

【scriptタグでdefer属性を設定する】------
この方法は JavaScript のコードを記述した外部のファイルを読み込む場合にだけ利用出来る。

defer 属性を設定された script タグで読み込まれた外部の JavaScript のファイルに記述されたコードは、すぐに実行されるのではなく DOM ツリーの構築が完了し DOMContentLoaded イベントが発生する直前に実行されます。
サンプル

jsファイル

ブラウザを立ち上げて、ボタンをクリックする
以上で、ジャバスクリプトのコード位置とその対策方について説明した。
コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする