JavaScriptのElementオブジェクトのイベント操作方法

JavaScriptでWebページを操作するときに発生するイベントの扱い方について解説します

イベント取得

Webページにフォームを作って操作したり、画面の表示に何か変化があったときに特定の動作をできるようにしたり、何かしらのイベントが発生したときのイベントを取得しする方法を解説します。

まずは昔から利用されている方法です。

これはブラウザのバージョンに依存することなく利用できます。

なので今でも広く使われています。

let el = document.querySelect('div');

// 関数を呼び出す方法
el.onclick = click;

function click(e) {
  /* ... 処理 ... */
}

// 関数式を使う方法
el.onclick = function(e) {
  /* ... 処理 ... */
}

このコードは選択されたdivタグの部分にクリックされたとき何らかの処理を行う例です。

要素上にイベントリスナーが既にある場合は置き換えてしまいます。

今でも広く使われているためよく見かけると思います。

addEventListenerを使う

この記事ではこれから主流になりつつある方法について説明します。

addEventListenerはDOM Level2のEvents仕様で導入されました。

現在ではこの方法でイベントを取得して何らかの処理をするのが主な手法になります。

ユーザ視点では昔からある方法とaddEventListenerを使った方法に違いはありません。

addEventListenerを使う利点は、おおまかには以下があげられます。

  • 他のライブラリを利用する場合でも上手く動作させることができる
  • より細かなコントロールができる
  • HTML要素以外の任意のDOM要素で動作できる

これらはコーディング上の利点になるかと思います。

実感できる利点かどうかは処理内容によると思いますが、ここではこれからよく見かけることになるだろうaddEventListenerについて説明します。

イベントの取得の基本的な考え方は昔からの方法と同じです。

その処理をaddEventListenerメソッドを使って行います。

書式)
 target.addEventListener(イベントの種類, 関数);
例)
let el = document.querySelect('div');

// 関数を呼び出す方法
el.addEventListener('click', click);
function click () {
  /* ... 処理 ... */
}

// 関数式を使う方法
el.addEventListener('click', () => {
  /* ... 処理 ... */
});

古い方法ではオブジェクトのプロパティを使って処理を書いていました。

これはその部分をaddEventListenerを呼び出して処理しています。

関数式を使った具体的な例を見てみましょう。

<body>
  <input type="text">
  <button>実行</button>
  <p>ここの表示が変わる</p>
  <p>上の表示に注目!</p>
  <script>
    let ipt = document.querySelector('input');
    let btn = document.querySelector('button');
    let para = document.querySelector('p');
    btn.addEventListener('click', () => {
      para.innerText = ipt.value;
    });
  </script>
</body>

このコードはテキストフィールドに入力した文字をボタンを押すとページ最初のpタグの場所に表示します。

JavaScriptを見ていくと、テキストフィールド、ボタン、pタグをquerySelectorを使ってオブジェクトを選択しています。

pタグは複数あるので最初に見つけたものを選択します。

ボタンが押されたかどうかのイベントを取得するので、ボタンのオブジェクトを使ってaddEventListenerを呼び出しています。

クリックされたときのイベントを処理したいので、イベントの種類は’click’となります。

例えば表示したテキストフィールドに「こんにちは」と入力してボタンを押すと、

<p>ここの表示が変わる</p>
↓
<p>こんにちは</p>

と変わるので「こんにちは」が表示されます。

pタグが複数ある場合に特定のpタグを処理したい場合は、id名やclass名を付けてターゲットを選択します。

<body>
  <input type="text">
  <button>実行</button>
  <p>ここの表示が変わる</p>
  <p id="change">上の表示に注目!</p>
  <script>
    let ipt = document.querySelector('input');
    let btn = document.querySelector('button');
    let para = document.querySelector('p');
    let change = document.querySelector('#change');    btn.addEventListener('click', () => {
      para.innerText = ipt.value;
      change.style = 'color:red';
    });
  </script>
</body>

このコードはボタンを押すと「<p id="change">上の表示に注目!</p>」の部分の文字が赤く表示します。

では、同じタグやclass名が複数あった場合に、その中の特定のもののイベントを取得するにはどうすればよいでしょうか。

その場合、まず複数ある同じ名前の要素は、querySelectorAllやgetElementsByClassNameなどを使って、オブジェクトのリストを取得します。

リストにある複数のオブジェクトから特定してイベントを取得します。

let elems = document.querySelectorAll('.tile');
for (let elem of elems) {
  elem.addEventListener('click', () => {
    /* ... 処理 ... */
  });
}

このコードはclass名がtileの複数ある要素を取得し、オブジェクト1つ1つにaddEventListenerを呼び出しています。

こうすることで同じclass名が複数あっても、クリックされた特定のオブジェクトのイベントを取得することができます。

以下のWebページの動きを見てみましょう。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Event Sample</title>
  <style>
    #panel {
      width: 320px;
      height: 320px;
    }

    .tile {
        width: 100px;
        height: 100px;
        line-height: 100px;
        border: 1px solid gray;
        text-align: center;
        font-size: 40px;
        font-weight: bold;
        float: left;
        cursor: pointer;
    }
  </style>
</head>
<body>
  <div id="panel">
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
    <div class="tile"></div>
  </div>
  <script>
    let elems = document.querySelectorAll('.tile');
    for (let elem of elems) {
      elem.addEventListener('click', () => {
        elem.style = 'background:blue';
      });
    }
  </script>
</body>
</html>

このコードは100px四方のdiv要素を3 x 3に並べて、クリックされた部分の背景色を青色に表示しています。

この動作をみることで特定の要素がクリックされたイベントを取得して処理していることがわかります。

そしてクリックされた要素が何番目の要素かを知るためには以下の方法で行います。

Array.from(elems).indexOf(elem);

querySelectorAllなどで取得するオブジェクトのリストは配列ではないため、一旦配列に変換してからインデックスを獲得します。

先程の処理にこのコードを追加してみましょう。

<script>  let elems = document.querySelectorAll('.tile');
  for (let elem of elems) {
    elem.addEventListener('click', () => {
      elem.style = 'background:blue';
      elem.innerText = Array.from(elems).indexOf(elem);
    });
  }
</script>

これでクリックされた要素の部分にインデックスが表示されます。

またfor文の記述を変えることで関数を使わずにインデックスを獲得することもできます。

for (let i = 0; i < elems.length; i++) {
  elems[i].addEventListener('click', () => {
      elems[i].style = 'background:blue';
      elems[i].innerText = i;
    });
}

オブジェクトのリストは配列ではありませんが、配列と同じように[]でアクセスすることができます。

こうすることで変数iがそのまま何番目の要素がクリックされたかを知ることができます。

この方法には注意点があります、for文でインデックスとして使う変数(この場合は変数i)は、letで宣言する必要があります。

もしvarで宣言してしまうとイベントが正しく処理されません。

それはletとvarではスコープが違うためで、varだとfor文内や関数内のスコープを超えてすべて同じ変数として扱われるため、繰り返しの最後に格納した数値だけが有効になってしまいます。

この記述方法のときは必ずletを使用してください。

利用できるイベントは以下の公式サイトを参照してください。

https://developer.mozilla.org/ja/docs/Web/Events

まとめ

JavaScriptは同じ目的でも複数の実装方法があります。

イベント操作もその1つで、JavaScriptをはじめて学習するときは1つの方法を理解して実装するようにして、ある程度時間が経ってから他の方法を見てみるのがいいかもしれません。

JavaScriptはどんどん新しくなっていってるので、新しい方法でかつある程度使われるものを学習するのがいいでしょう。

イベントに関してはaddEventListenerを使うことをおすすめします。