Ne:Code道場~JavaScript DOM⑥(イベント③)の巻~



Ne:Code道場~JavaScript DOM⑥(イベント③)の巻~

プログラミング学習で、漫画など視覚的なものと併用すると楽しく継続的に学んでゆける人も多いと思います。そこでこの連載では、猫の漫画を交えつつ、JavaScriptのDOMのイベントの学習ポイントについて紹介します。

目次
  1. はじめに
  2. イベントを登録するタイミングをなぜ意識しないといけないニャ?
  3. どうしてhead内だとDOM要素を見つけられなかったニャ?
  4. イベントの書き方の違いが気になるニャ
  5. scriptタグのどういう属性を使うニャ?
  6. 最後に

はじめに

image この記事ではJavaScriptのDOMのイベントの3回目としてイベント登録のタイミング(DOM関連の操作を行うタイミング)について、概要について取り上げつつ、躓きポイント を補足しています。 各節ごとに、Ne:Code道場(猫de道場)の弟子猫がポイントをまとめ、最後に師匠猫がそれらを総括して3ポイントでまとめています。 それらのポイントを中心に、DOMのイベントについて理解を深めてゆきましょう。

イベントを登録するタイミングをなぜ意識しないといけないニャ?

前回の記事では、イベント実行時に自動で渡されているイベント引数について概要を取り上げました。今回は、イベントを登録するタイミング関連で注意点を踏まえつつ見てゆきます。
DOMに紐づくイベント(ボタンのクリックや入力変更等)は、そもそも該当するDOMが存在していないと登録することができません。どういうことでしょう。まずは例からみてゆきましょう。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>お試しHTMLニャ</title>
  <!-- ニャ?!今回の例ではこれみよがしにscriptファイルの読み込みがheadに書いてあるニャ?  -->
  <!-- 今までのイベント関連の記事ではいつもbodyタグの終了間際でscriptファイルを読み込んでいたはずニャ!  -->
  <script src="script.js"></script>
</head>
<body>
  <!-- id属性に「btn」と設定されているボタンが一つだけ配置されているニャ!  -->
  <button id="btn">アラートを表示するニャ</button>
</body>
</html>

猫弟子のコメントにもありますが、今までは、bodyの終了タグ手前でscript.jsファイルを読み込んでいました。それは今回の記事で取り上げようと思っていた内容を一旦後回しにしていたためです。
まず、headタグの中でJavaScriptファイルを読み込むこと、それ自体は特に問題はありません。しかし、そのJavaScriptの処理内でDOM関連の操作をしようと思っていた際に注意するポイントがでてきます。
JavaScriptのファイルを見ながら確認してゆきましょう。

// ニャ!今までのイベントで学んだ内容を踏まえてボタンクリックイベントを登録しているニャ
// ニャニャ?!でもファイルをブラウザで表示したらエラーが起きているニャ?
// どうやらボタンのDOM要素を取得できていないようニャ?id名は間違ってないのにニャ?
document.getElementById("btn").addEventListener("click" , (event) => {
  alert("今回はシンプルにアラート表示する例ニャ");
});

猫弟子のコメントにもあるように、画面表示時にすでにエラーが起きているのが確認できるでしょう。試しに、JavaScriptの方は変更せず、HTML側のscript.jsを読み込んでいる一行を、今までのイベント記事の例と同様、bodyタグの終了間際に移動してみましょう。その結果再度画面表示をしてみますと、エラーが発生すること無く、ボタンを押せばアラートのメッセージが表示されることを確認できるでしょう。
image

どうしてhead内だとDOM要素を見つけられなかったニャ?

HTMLファイル内部は上から順次実行されてゆくという特性があるため、headに記載されているスクリプトが実行されたタイミングでは、そこより下に書いてあるbodyのボタン要素を見つけることはできません。
もしも、head内に記載する場合は、画面読み込み後のタイミングでDOM関連の処理を実行する必要があります。
具体的に見てゆきましょう。

// ニャ?さっきまで書いてあった処理が、まるごと、無名関数として、「window.onload」に設定されているニャ!
window.onload = () => {
  document.getElementById("btn").addEventListener("click" , (event) => {
    alert("今回はシンプルにアラート表示する例ニャ");
  });
};

上記のように書き換えると、画面表示時にエラーが起きることなく、その後のボタンクリックでも正常に動作することを確認できるでしょう。
 
windowはその名前の通り、DOMの大親分とも言える画面全体を包括している要素で、それの読み込み時(load)に行いたい処理をonloadに設定しているコードになります。
その結果、HTMLファイルの下まで読み込まれたあとにonload内の処理が実行されるので、ボタン要素を無事見つけ出すことができているのです。
image

イベントの書き方の違いが気になるニャ

これ以前のイベント関連の記事では、「addEventListener」を用いてイベント登録を行っていました。今回の例では「onXxx」でイベント登録をしています。
「addEventListener」の方がより後にJavaScriptで利用できるようになった書き方で、古株は「onXxx」の書き方です。
なので、クリックイベントも「onclick」で記載することも可能です。
基本的な動きは同じになりますが、そこには大きな違いがあります。
ここではその違いの一つを見てゆきましょう。
まず、HTML側はこちらです。
 

<!-- 今回は例としてbodyの中だけ抜粋しているニャ!  -->
<body>
  <!-- ボタンが2つ配置されているニャ  -->
  <button id="btnYes">Yesニャ</button>
  <button id="btnNo">Noニャ</button>
  <!-- 今回の例ではonXxxとaddEventListenerの違いがメインニャ -->  
  <!-- なのでJavaScriptのコードを減らすためにスクリプトはまたbodyの下で読み込んでいるニャ〜  -->
  <script src="script.js"></script>
</body>

そして、JavaScript側はこちらになります。

// ボタンそれぞれ2回ずつイベントを登録する都合で、一旦変数にキープしてるニャ
let btnYes = document.getElementById("btnYes");
let btnNo = document.getElementById("btnNo");
// 「Yes」ボタンは、「addEventListener」形式で二回登録してるニャ
btnYes.addEventListener("click" , (event) => {
  alert("はいニャ");
});
btnYes.addEventListener("click" , (event) => {
  alert("もう一回、はいニャ");
});
// 「No」ボタンは、「onclick」形式で二回登録してるニャ
btnNo.onclick = () => {
  alert("いいえニャ");
});
btnNo.onclick = () => {
  alert("断固NOニャ!");
});

こちらを実行すると、「Yes」ボタンを押したときは、アラートが2回(「はいニャ」「もう一回、はいニャ」)が表示されますが、「No」ボタンを押した場合は、アラートが1回のみ(「断固NOニャ!」と、2個めに登録した方のonclickでのalert)の表示になっていることを確認できるでしょう。
 
addEventListenerでは、同じイベントを何回でも登録出来ますが、onclickは、onclickというプロパティに直接代入(=)しているその記載の通り、紐付くイベント処理は一つしか設定できず、何回も設定場合は、毎回新しく設定したイベント処理で上書きされてゆくのです。
 
以上、画面読み込みの書き方から、onXxx形式のイベント登録について見てきました。最後に、scriptタグの持っている属性を活用することで、HTML側からJavaScriptの読み込みタイミングを制御する方法も見てみましょう。
image

scriptタグのどういう属性を使うニャ?

defer属性を用いることで、画面の準備ができてからscriptを実行することも可能です。
まず、HTML側はこちらです。

<head>
  <!-- head内の一部だけ抜粋しているニャ  -->
  <!-- defer属性を追加したらエラーにならなくなったニャ♪  -->
  <script src="script.js" defer></script>
</head>

そして、JavaScript側はこちらになります。

// JavaScript側は画面読み込み後の処理を入れる前のものに戻しているニャ
// 画面読み込み後にエラーが発生することは無く、ボタンクリックしたらちゃんとアラートが表示されているニャ!
document.getElementById("btn").addEventListener("click" , (event) => {
  alert("今回はシンプルにアラート表示する例ニャ");
});

deferは論理属性なので、属性名を記載するのみで設定がオンになります。この属性が付与されている場合は、HTML上の記載されている行でJavaScriptファイルは読み込まれず、画面の表示準備が終わってから読み込みが行われるようになるのです。そのため、DOMも読み込み済みになっているのでアクセス可能になります。
JavaScript側だけで無く、HTMLの設定でもタイミングを制御することが可能なのですね。
image

最後に

DOM操作のタイミングと、その延長でイベント記載のバリエーションについて、猫弟子がいくつか上げたポイントを、猫師匠が厳選3ポイントでまとめたのがこちらです。

  1. HTMLファイルは上から順に読み込まれてゆく特性があるニャ
    1. なので、JavaScriptからHTMLのDOM要素を操作する場合は、その要素が読込済かどうかを意識するニャ
    2. HTMLのscriptタグのdefer属性でもそのタイミングは制御可能ニャ
  2. head要素内に記載するJavaScriptからDOM要素を操作する場合は、画面読み込み後に実行されるように書くニャ
    1. 「画面読み込み後」というイベントが用意されているので、それを用いることで画面読み込み後に処理を記載することが可能になるニャ
  3. イベント記載のバリエーションについて確認したニャ
    1. 「onXxx」形式でのイベント登録は必ず一つ、「addEventListener」では複数個登録可能という動きの違いを見てみたニャ。それぞれの挙動の違いを抑えておくニャ

DOMに関連して、6つ目の記事として、DOM操作のタイミングについて学びました。JavaScriptの本領発揮としてのDOM関連の処理を学ぶことで、JavaScriptとしてできることがぐっと高まってゆくと思います。
するとコードへの理解も深まり、プログラミングが更に楽しくなってくるでしょう。
DOMに関連する知識をしっかり身につけつつ、今後の学習に繋げてゆきましょう。
image

小泉七菜
この記事を書いた人
小泉七菜
\ 無料体験開催中!/自分のペースで確実に習得!
オンライン・プログラミングレッスンNo.1のCodeCamp