JavaScriptにおけるイベント処理

By | March 13, 2022

ブラウザの仕組み

HTMLドキュメントにおけるコードの実行順序

コードは上から順に実行されていく。

従って、操作対象のDOM要素(=HTML要素)よりも先にJavaScriptを記述するとエラーが発生する。

ただし、①ブラウザにDOM要素がキャッシュされている場合②レンダリングエンジンとJSエンジンの並列処理において、運よく該当のJSコードが先に処理された場合はこの限りではない。

適切に動作しないコードの例↓

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
<script>
  neko.onclick = function(){
    alert('ろに');
}
</script>
<button id="neko">わろろん</button>
</body>
</html>

実行順序問題の回避策

「自分より後に記述されたDOM要素を処理ができない」という問題の回避策は下記の二つである。

①JSを必ずHTMLドキュメントの一番最後に配置する(=JS実行時点で必ず全てのDOM要素がレンダリングされているようにする)

②window.onload(※ページの読み込みの完了を示すイベント)の無名関数内で全てのJSが動作するようにする。

<script>
window.onload = function(){
  neko.onclick = function(){
    alert('ろに');
  }
}
</script>

DOM

「DOM(Document Object Model)」とは、HTML Documentの全要素をObject(=Node)として表現するプログラミングインターフェースを指す。

こうしたHTML Documentの全要素(=DOM要素)は、JavaScriptにより操作可能である。

イベント

「イベント」とはブラウザ上における任意のイベント(例:マウス操作・キーボード操作)を指す。

イベントの検出に基づき、任意の処理を実行することを「イベント処理」という。

イベントハンドラ

「イベントハンドラ」は特定のイベントの発生時に実行される関数を指す。

①on<event>属性としてHTML上でonclickハンドラを定義した場合の例↓

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
<button onclick="warota1()">わろろん</button>
<button onclick="warota2()">ねころん</button>
<button onclick="warota3()">ぴころん</button>
<button onclick="warota4('araara')">あらあら</button>
<script>
function warota1(){
  alert('ぷに');
}
function warota2(){
  alert('むに');
}
function warota3(){
  document.write('むに');
}
function warota4(arg){
  document.write(arg);
}
</script>
</body>
</html>

②on<event>のDOMプロパティを利用してonlickハンドラを割り当てた場合の例↓

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
<button id="neko">わろろん</button>
<script>
  neko.onclick = function(){
    alert('ろに');
}
</script>
</body>
</html>

③イベントリスナを利用してonclickハンドラを割り当てた場合の例↓(※イベントリスナを利用することで、単一のイベントに対して複数の処理を割り当てることができるようになっている)

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
<button id="neko">わろろん</button>
<script>
  function handler1() {
    alert('cat');
  };
  function handler2() {
    alert('cat2');
  }
  var elem = document.getElementById("neko");
  elem.addEventListener("click", handler1);
  elem.addEventListener("click", handler2);
</script>
</body>
</html>

イベントオブジェクト

発生したイベントの詳細情報は、ブラウザにより自動的にイベントオブジェクトに格納される(=イベントオブジェクトが自動生成される)ため、ハンドラの引数としてオブジェクトを指定することで詳細情報をメソッド内で利用することが可能となる。

<input type="button" value="Click me" id="neko">

<script>
  neko.onclick = function(event) {
    alert(event.type + " at " + event.currentTarget);
    alert("Coordinates: " + event.clientX + ":" + event.clientY);
  };
</script>

オブジェクトのイベント

なお、上記コードにおいて、ノードのonclickに無名関数を代入することも可能である。

これはJavaScriptのオブジェクトが①メソッド②プロパティ③イベントの三要素で成立していることを示す顕著な例と言える。

<input type="button" value="Click me" id="neko">

<script>
  neko.onclick = function() {
    alert('ねこ');
  };
</script>

オブジェクトハンドラ

addEventListenerのハンドラとして”オブジェクト”を指定した場合、そのhandleEventメソッドが自動的に呼び出される。

<button id="element">Click</button>

<script>
  class Menu {
    handleEvent(event) {
      switch(event.type) {
        case 'mousedown':
          element.innerHTML = "Mouse down";
          break;
        case 'mouseup':
          element.innerHTML += "Mouse up";
          break;
      }
    }
  }

  let menu = new Menu();
  element.addEventListener('mousedown', menu);
  element.addEventListener('mouseup', menu);
</script>