この翻訳は不完全です。英語から この記事を翻訳 してください。
概要
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
: ABoolean
that indicates that events of this type will be dispatched to the registeredlistener
before being dispatched to anyEventTarget
beneath it in the DOM tree.once
: ABoolean
indicating that thelistener
should be invoked at most once after being added. If it istrue
, thelistener
would be removed automatically when it is invoked.passive
: ABoolean
indicating that thelistener
will never callpreventDefault()
. 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 aBoolean
defining if the listener is added to the system group.
useCapture
Optional- 捕捉フェーズを使用する場合は、
useCapture
にtrue
を指定します。捕捉フェーズの開始後、指定されたタイプのイベントの全てが、まず、登録されたlistener
に発送され、その後、DOM ツリーにおいてその下に位置する任意のEventTarget
に発送されます。ツリーをたどって上方へ浮上するイベントは、捕捉フェーズを用いるように指定されたリスナーを誘発することはありません。詳細については、DOM Level 3 Events を参照してください。この引数は、全てのブラウザで省略可能ではないことに注意してください。省略した場合、useCapture
はfalse
となります。 -
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 isfalse
for chrome andtrue
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になります。)
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)
.
仕様書
Specification | Status | Comment |
---|---|---|
DOM EventTarget.addEventListener() の定義 |
現行の標準 | |
DOM4 EventTarget.addEventListener() の定義 |
勧告 | |
Document Object Model (DOM) Level 2 Events Specification EventTarget.addEventListener() の定義 |
勧告 | Initial definition |
ブラウザ互換性テーブル
Feature | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari (WebKit) |
---|---|---|---|---|---|
Basic support | 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 ( |
49 (49) | 未サポート | 未サポート | 未サポート |
once value in the options parameter |
未サポート | 未サポート | 未サポート | 未サポート | 未サポート |
Feature | Android | Android Webview | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile | Chrome for Android |
---|---|---|---|---|---|---|---|
Basic support | 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
.
関連項目
EventTarget.removeEventListener
- カスタムイベントの作成とトリガリング
- More details on the use of
this
in event handlers