この翻訳は不完全です。英語から この記事を翻訳 してください。

概要

addEventListener は、1 つのイベントターゲットにイベントリスナーを 1 つ登録します。イベントターゲットは、ドキュメント上の単一のノード、ドキュメント自身、ウィンドウ、あるいは、XMLHttpRequest です。

ターゲットに対して 2 つ以上のイベントリスナーを登録するには、同じターゲットに対して、異なるイベントタイプ、あるいは、キャプチャパラメータを指定して addEventListener() を呼び出します。

構文

target.addEventListener(type, listener[, options]);
target.addEventListener(type, listener [, useCapture]);
target.addEventListener(type, listener [, useCapture, aWantsUntrusted  ]); // Gecko/Mozilla のみ

パラメーター

type
対象とするイベントの種類を表す文字列
listener
指定されたタイプのイベントが発生するときに通知を受け取るオブジェクト。これは、EventListener インタフェースを実装するオブジェクト、あるいは、単純に、JavaScript の関数でなければなりません。
options Optional
そのイベントリスナーについての特性を指定するオプションのオブジェクトです。これらのオプションが使用できます
  • capture: A Boolean that indicates that events of this type will be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree. 
  • once: A Boolean indicating that the listener should be invoked at most once after being added. If it is true, the listener would be removed automatically when it is invoked.  
  • passive: A Boolean indicating that the listener will never call preventDefault(). If it does, the user agent should ignore it and generate a console warning.
  • mozsystemgroup: Available only in code running in XBL or in Firefox' chrome, it is a Boolean defining if the listener is added to the system group.
useCapture Optional
捕捉フェーズを使用する場合は、 useCapturetrue を指定します。捕捉フェーズの開始後、指定されたタイプのイベントの全てが、まず、登録された listener発送され、その後、DOM ツリーにおいてその下に位置する任意の EventTarget発送 されます。ツリーをたどって上方へ浮上 するイベントは、捕捉フェーズを用いるように指定されたリスナーを誘発することはありません。詳細については、DOM Level 3 Events を参照してください。この引数は、全てのブラウザで省略可能ではないことに注意してください。省略した場合、 useCapturefalse となります。
Note: For event listeners attached to the event target; the event is in the target phase, rather than capturing and bubbling phases. Events in the target phase will trigger all listeners on an element regardless of the useCapture parameter.
Note: useCapture became optional only in more recent versions of the major browsers; for example, it was not optional before Firefox 6. You should provide this parameter for broadest compatibility.
WantsUntrusted
true の場合、このリスナーはウェブコンテンツによって発火された合成イベント(カスタムイベント) を受け取ります (the default is false for chrome and true for regular web pages)。This parameter is only available in Gecko and is mainly useful for the code in add-ons and the browser itself. 特権ページと非特権ページの間のやり取りを参照してください。

Add a simple listener

HTML Content

<table id="outside">
    <tr><td id="t1">one</td></tr>
    <tr><td id="t2">two</td></tr>
</table>

JavaScript Content

// Function to change the content of t2
function modifyText() {
  var t2 = document.getElementById("t2");
  if (t2.firstChild.nodeValue == "three") {
    t2.firstChild.nodeValue = "two";
  } else {
    t2.firstChild.nodeValue = "three";
  }
}

// add event listener to table
var el = document.getElementById("outside");
el.addEventListener("click", modifyText, false);

上記の例では、modifyText()addEventListener() を用いて登録された click イベントのリスナーになっています。table 中のどこをクリックしても、そのハンドラまでバブルアップし、modifyText() が実行されます。

リスナー関数に引数を渡す場合は、関数式を使う必要があります。

Event Listener with anonymous function

HTML Content

<table id="outside">
    <tr><td id="t1">one</td></tr>
    <tr><td id="t2">two</td></tr>
</table>

JavaScript Content

// Function to change the content of t2
function modifyText(new_text) {
  var t2 = document.getElementById("t2");
  t2.firstChild.nodeValue = new_text;    
}
 
// Function to add event listener to table
var el = document.getElementById("outside");
el.addEventListener("click", function(){modifyText("four")}, false);

注記

なぜ、addEventListener を使うのですか?

addEventListener は、W3C DOM で仕様化された、イベントリスナーを登録するための方法です。その利点は以下の通りです。

  • イベントに 1 つ以上のハンドラを追加することができます。これは、特に、他のライブラリ/拡張で利用しても上手く動作する必要がある DHTML ライブラリや Mozilla の拡張 のために役立ちます。
  • リスナーがアクティブ化されたときに、その動きを細かくコントロールすることを可能にします(キャプチャリング 対 バブリング)。
  • HTML 要素だけでなく、任意の DOM 要素 で動作します。

もうひとつの方法である、イベントリスナーを登録するための古い方法 は、後で説明します。

イベント発送中のリスナーの追加

EventListener がイベント処理中に EventTarget に追加された場合、それが現在のアクションによって実行されることはありませんが、浮上フェーズのように、後の段階のイベントフローで実行されるかもしれません。

複数の同一のイベントリスナー

複数の同一の EventListener が、同じ EventTarget に同じ引数で登録された場合、重複するインスタンスは反映されません。EventListener が 2 度呼び出されることはなく、重複するインスタンスは反映されないので、removeEventListener で手動で削除する必要はありません。

ハンドラー内での this の値

一連の類似した要素に対して一般的なハンドラーを用いたいというような、イベントハンドラーが実行される要素を参照したいということがたびたびあります。

addEventListener() を使って要素にハンドラー関数を設定したとき、ハンドラーの中の this の値は要素への参照となります。これはハンドラーに渡された event 引数の currentTarget プロパティの値と同じです。

onclick のようなイベント属性がHTML要素に指定されていた場合、イベント属性のJavascirptコードの値は事実上addEventListener()を使用するような方法でthisの値をバインドするハンドラー関数に置き換えられます。an occurrence of this within the code represents a reference to the element. Note that the value of this inside a function called by the code in the attribute value behaves as per standard rules. 従って、以下のような場合:

<table id="t" onclick="modifyText();">
. . .

onclick イベントで呼び出されたときの modifyText() 内の this の値は、グローバル (window) オブジェクトへの参照となります。 (もしくは strict mode の場合、undefined になります。)

注: JavaScript 1.8.5 で Function.prototype.bind() メソッドが導入されました。これは呼び出す関数内で this に相当する値を指定できるものです。これを使えば、関数がどこから呼び出されるかによって this の値が変わってしまうというややこしい問題を簡単に回避できます。ただし、リスナーを後で削除できるように、そのリスナーへの参照を残しておく必要があります。

以下は bind を使った場合と使わない場合の例です。

var Something = function(element) {
  this.name = 'Something Good';
  this.onclick1 = function(event) {
    console.log(this.name); // this は element なので undefined になります
  };
  this.onclick2 = function(event) {
    console.log(this.name); // this はバインドされた Something オブジェクトなので「Something Good」と出力されます
  };
  element.addEventListener('click', this.onclick1, false);
  element.addEventListener('click', this.onclick2.bind(this), false); // これが仕掛けです
}

上の例の問題は、bind の付いたリスナーを削除できないということです。もうひとつの解決策は、あらゆるイベントを捕捉する handleEvent という特別な関数を使用することです。

var Something = function(element) {
  this.name = 'Something Good';
  this.handleEvent = function(event) {
    console.log(this.name); // this は Something オブジェクトなので「Something Good」と出力されます
    switch(event.type) {
      case 'click':
        // 処理
        break;
      case 'dblclick':
        // 処理
        break;
    }
  };

  // この場合のリスナーは this であって this.handleEvent でないことに注意してください
  element.addEventListener('click', this, false);
  element.addEventListener('dblclick', this, false);

  // リスナーは適切に削除できます
  element.removeEventListener('click', this, false);

  element.removeEventListener('dblclick', this, false);
}

古い Internet Explorer と attachEvent

IE9 より前の Internet Explorer では、標準の addEventListener ではなく、 attachEvent を使わなければなりません。IE をサポートするためには、上記の例を以下のように修正しなけれなりません。

if (el.addEventListener){
  el.addEventListener('click', modifyText, false);
} else if (el.attachEvent){
  el.attachEvent('onclick', modifyText);
}

attachEvent の欠点が 1 つあります。this の値がイベントを起こした要素ではなく、window オブジェクトへの参照になってしまうことです。

互換性

You can work around the addEventListener, removeEventListener, Event.preventDefault and Event.stopPropagation not being supported by IE 8 using the following code at the beginning of your script. The code supports the use of handleEvent and also the DOMContentLoaded event.

Note: useCapture is not supported, as IE 8 does not have any alternative method of it. Please also note that the following code only adds support to IE 8.

Also note that this IE8 polyfill ONLY works in standards mode: a doctype declaration is required.

(function() {
  if (!Event.prototype.preventDefault) {
    Event.prototype.preventDefault=function() {
      this.returnValue=false;
    };
  }
  if (!Event.prototype.stopPropagation) {
    Event.prototype.stopPropagation=function() {
      this.cancelBubble=true;
    };
  }
  if (!Element.prototype.addEventListener) {
    var eventListeners=[];
    
    var addEventListener=function(type,listener /*, useCapture (will be ignored) */) {
      var self=this;
      var wrapper=function(e) {
        e.target=e.srcElement;
        e.currentTarget=self;
        if (typeof listener.handleEvent != 'undefined') {
          listener.handleEvent(e);
        } else {
          listener.call(self,e);
        }
      };
      if (type=="DOMContentLoaded") {
        var wrapper2=function(e) {
          if (document.readyState=="complete") {
            wrapper(e);
          }
        };
        document.attachEvent("onreadystatechange",wrapper2);
        eventListeners.push({object:this,type:type,listener:listener,wrapper:wrapper2});
        
        if (document.readyState=="complete") {
          var e=new Event();
          e.srcElement=window;
          wrapper2(e);
        }
      } else {
        this.attachEvent("on"+type,wrapper);
        eventListeners.push({object:this,type:type,listener:listener,wrapper:wrapper});
      }
    };
    var removeEventListener=function(type,listener /*, useCapture (will be ignored) */) {
      var counter=0;
      while (counter<eventListeners.length) {
        var eventListener=eventListeners[counter];
        if (eventListener.object==this && eventListener.type==type && eventListener.listener==listener) {
          if (type=="DOMContentLoaded") {
            this.detachEvent("onreadystatechange",eventListener.wrapper);
          } else {
            this.detachEvent("on"+type,eventListener.wrapper);
          }
          eventListeners.splice(counter, 1);
          break;
        }
        ++counter;
      }
    };
    Element.prototype.addEventListener=addEventListener;
    Element.prototype.removeEventListener=removeEventListener;
    if (HTMLDocument) {
      HTMLDocument.prototype.addEventListener=addEventListener;
      HTMLDocument.prototype.removeEventListener=removeEventListener;
    }
    if (Window) {
      Window.prototype.addEventListener=addEventListener;
      Window.prototype.removeEventListener=removeEventListener;
    }
  }
})();

イベントリスナーを登録するための古い方法

addEventListener() は、DOM 2 Events 仕様で導入されました。それ以前は、以下のようにイベントリスナーを登録していました。

// 関数へのリファレンスを利用する方法—'()' が無いことに注意してください
el.onclick = modifyText;

// 関数式を利用する方法
element.onclick = function() {
   /* ...文... */
};

このメソッドは、要素上に click イベントリスナーが既に存在する場合、置き換えてしまいます。
【訳注: これはつまり、既に要素に対し定義されたハンドラに対し更にイベントを追加しようとする場合に、以前のイベントを含める形で上書きしなければならない事を意味します。】
他のイベント、blur (onblur)、keypress (onkeypress)、などのような関連するイベントハンドラも同様です。

これは本質的には DOM 0 の一部分なので、この方法は、非常に広くサポートされており、特別なクロスブラウザ用のコードも必要ありません。それ故、addEventListener() の独自の機能が必要でない場合に、動的にイベントリスナーを登録する方法として普通に使われています。

メモリに関する問題

var i;
var els = document.getElementsByTagName('*');

// ケース 1
for(i = 0; i < els.length ; i++){
  els[i].addEventListener("click", function handler(e){/*関数の処理*/}, false);
}

// ケース 2
function processEvent(e){
  /*関数の処理*/
}

for(i = 0; i < els.length ; i++){
  els[i].addEventListener("click", processEvent, false);
}

最初の例では、新しい匿名関数式がループごとに作られています。これに対して 2 番目の例では、前に宣言された同じ関数がイベントハンドラとして使われています。そのため、メモリの消費が抑えられます。 Moreover, in the first case, since no reference to the anonymous functions is kept, it is not possible to call element.removeEventListener because we do not have a reference to the handler, while, in the second case, it's possible to do myElement.removeEventListener("click", processEvent, false).

Improving scrolling performance with passive listeners

var elem = document.getElementById('elem');
elem.addEventListener('touchmove', function listener() {
  /* do something */
}, { passive: true });

This way a touchmove listener will not block while a user is scrolling (same applies to wheel events). Demo available here (Google Developers Page).

Beware: Browsers who do not support event listener options will see the 3rd argument as useCapture and therefore as true.

 

仕様書

Specification Status Comment
DOM
EventTarget.addEventListener() の定義
現行の標準  
DOM4
EventTarget.addEventListener() の定義
勧告  
Document Object Model (DOM) Level 2 Events Specification
EventTarget.addEventListener() の定義
勧告 Initial definition

ブラウザー互換性テーブル

機能 Chrome Firefox (Gecko) Internet Explorer Opera Safari (WebKit)
基本サポート 1.0[1][2] 1.0 (1.7 or earlier)[3] 9.0[4] 7 1.0[1]
useCapture made optional 1.0 6 (6) 9.0 11.60 (有)
options parameter (with capture and passive values)[5]

49.0 (capture) 51.0 (passive)

49 (49) 未サポート 未サポート Landed in Nightly WebKit bug 158601
once value in the options parameter 55 50 (50) 未サポート 未サポート Landed in Nightly WebKit bug 149466
機能 Android Android Webview Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile Chrome for Android
基本サポート 1.0

(有)[2]

1.0 (1.0)[3] 9.0 6.0 1.0[1]

(有)[2]

useCapture made optional ?

(有)

6.0 (6) ? ? ?

(有)

options parameter (with capture and passive values)[5] 未サポート 49.0 (capture) 51.0 (passive) 49.0 (49) ? ? ? 49.0 (capture) 51.0 (passive)

[1] WebKit で useCapture 引数が明示的に省略可能となったのは、 2011 年の 6 月 ですが、変更以前でも動作していました。この変更は、 Safari 5.1 と Chrome 13 から実装されます。

[2] Before Chrome 49, the type and listener parameters were optional.

[3] Firefox 6 より前では、 useCapture の引数を省略した場合、例外が発生します。Gecko 9.0 (Firefox 9.0 / Thunderbird 9.0 / SeaMonkey 2.6) より前では、 addEventListener() のリスナー引数が null の場合、例外が発生します。現在では例外は発生せず、何も処理をしません。

[4] Older versions of Internet Explorer support the proprietary EventTarget.attachEvent method instead.

[5] For backwards compatibility, browsers that support options allow the third parameter to be either options or Boolean.

関連項目

ドキュメントのタグと貢献者

 最終更新者: dskmori,