uhyohyo.net

JavaScript初級者から中級者になろう

三章第二回 イベントリスナ

このページの最終更新日:

addEventListener

前回はJavaScriptから要素にイベントを登録する(イベントが起こったとき関数が呼ばれるようにする)方法として、イベントプロパティによる方法を紹介しました。

しかし、それは諸々の点から推奨されない方法でした。今回はよりDOM的にイベントを登録する方法としてaddEventListenerを紹介します。

<!doctype html>
<html>
  <head>
    <title>test</title>
  </head>
  <body>
    <p id="abcd">test</p>

    <script type="text/javascript">
      function aaa(){
          console.log('aaa!');
      }

      var p = document.getElementById('abcd');

      p.addEventListener('click', aaa, false);
    </script>
  </body>
</html>

このサンプルで、p要素をクリックすると、aaa関数が実行されます。これは、もちろんaddEventListenerによるものです。

これはノードが持つメソッドで、見て分かるように3つの引数をとります。

一つ目の引数はイベント名です。今回の場合'click'ですね。「onclick」のようにonはつかないことに注意しましょう。ここで指定したイベントの種類について、イベントが登録されます。つまり、今回の場合、クリックした場合のイベントを登録しています。

二つ目の引数はイベントリスナです。イベントリスナとは、要するに呼び出される関数のことです。関数のオブジェクト一章第四回)を渡しています。

さて、三つめの引数はフェーズの設定です。これについては三章第四回で説明するので、今はとりあえずfalseにしておきましょう。

まとめると、この関数はイベントが発生したときに呼ばれる関数を登録します。今回の場合は「clickが起こったとき(クリックされたとき)に関数aaaを呼ぶ」という設定をしているのでした。

これは、p.onclick = aaa;と同じような動作をしますね。

利点

さて、このメソッドを使うことにどんな利点があるかを紹介したいと思います。一つに、複数登録できるということがあります。

<!doctype html>
<html>
  <head>
    <title>test</title>
  </head>
  <body>
    <p id="abcd">test</p>

      <script type="text/javascript">
        function aaa(){
            console.log('aaa!');
        }
        function bbb(){
            console.log('bbb!');
        }

        var p = document.getElementById('abcd');

        p.addEventListener('click', aaa, false);
        p.addEventListener('click', bbb, false);
    </script>
  </body>
</html>

addEventListenerで関数aaaを登録したあと、続けて関数bbbも登録しています。

このサンプルでp要素をクリックしてみると、なんとログが2回表示されます。これから、関数aaaとbbbが両方呼ばれたことが分かります。

これは、前回のイベントプロパティを使う方法とは異なる点のひとつです。

p.onclick = aaa;
p.onclick = bbb;

のように2回関数を代入すると上書きされてしまうことは、前回説明しました。

つまり、addEventListenerを使えば上書きされずに追加されるということです。これなら前回説明した問題点を解消することができます。

JavaScriptからイベントを登録するときは、このaddEventListenerを使うようにしましょう。

removeEventListener

反対に、登録されているイベントをなくすというメソッドもあります。それがremoveEventListenerです。使い方はaddEventListenerと同じで、まったく同じ引数3つを渡します。

<!doctype html>
<html>
  <head>
    <title>test</title>
  </head>
  <body>
    <p id="abcd">test</p>

    <script type="text/javascript">
      function aaa(){
          console.log('aaa!');
      }

      var p = document.getElementById('abcd');

      p.addEventListener('click', aaa, false);
      p.removeEventListener('click', aaa, false);
    </script>
  </body>
</html>

上のほうのサンプルにremoveEventListenerの一行を追加したことで、p要素をクリックしてもログが表示されなくなりました。引数はまったく同じです。

なお、2つめの引数はaddEventListenerに渡したのと同じ関数オブジェクトである必要があります。例えば、次のように無名関数を使ってイベントを登録・削除しようとしてもうまくいきません。


<!doctype html>
<html>
  <head>
    <title>test</title>
  </head>
  <body>
    <p id="abcd">test</p>

    <script type="text/javascript">
      var p = document.getElementById('abcd');

      // イベントを登録
      p.addEventListener('click', function(){
        console.log('aaa!');
      }, false);

      // イベントを解除したつもり
      p.removeEventListener('click', function(){
        console.log('aaa!');
      }, false);
    </script>
  </body>
</html>

この例を実行してp要素をクリックするとログが表示されます。つまり、removeEventListenerでイベントリスナの登録を解除できていないということです。なぜかというと、function(){ 〜 }という式はその場で新しい無名関数を作るので、addEventListenerに渡された無名関数とremoveEventListenerに渡された無名関数は処理が全く同じであっても別々の関数オブジェクトになるからです。removeEventListenerには登録時と同じ関数オブジェクトを渡さないといけないので、これでは消えません。この例のように、いちど無名関数を登録してしまったら消せません。消す予定がないならそれでも構いませんが、あとで消したいものには名前をつける(変数に入れて参照できるようにする)必要があります。

removeEventListenerの活用例のひとつは、1回だけ実行されるようなイベントを作ることです。これを実現するには、一度イベントが呼ばれたらイベントリスナの登録を解除すればよいのです。具体的には、次のようにします。


<!doctype html>
<html>
  <head>
    <title>test</title>
  </head>
  <body>
    <p id="abcd">test</p>

    <script type="text/javascript">
      var p = document.getElementById('abcd');

      // イベントリスナ
      var handler = function(){
        console.log('foo!');
        p.removeEventListener('click', handler, false);
      };
      
      p.addEventListener('click', handler, false);
    </script>
  </body>
</html>