.addEventListener()
要素にイベントハンドラを登録します。
EventTarget.addEventListener()
メソッドは、
指定したリスナーをEventTarget上に登録し、
それを呼び出します。
イベントのターゲットはdocument内の要素かもしれませんし、
document自身、Window、
またはその他のイベントがサポートされたオブジェクト(例えば、XMLHttpRequestのような)かもしれません。
文法
target.addEventListener(type, listener[, useCapture]);
target.addEventListener(type, listener[, useCapture, wantsUntrusted ]); // Gecko/Mozillaのみ
引数 | 説明 |
---|---|
type |
型: リッスンするイベントのタイプの文字列を指定します。 |
listener |
型: 指定したtypeのイベントが発生した際に、通知を受け付けるオブジェクトです。 これはEventListenerインターフェースを実装したオブジェクトか、 シンプルなJavaScript関数でなければいけません。 |
[useCapture] |
型: trueを指定すると、useCaptureはユーザーがキャプチャ開始を望んでいることを指し示します。 キャプチャ開始後は、イベントがDOMツリー内のそのEventTarget下に送られる前に 指定されたtypeの全てのイベントが登録されたリスナーに送られます。 ツリーを通してバブルアップ(浮上)するイベントは、useCapture指定されたリスナーをトリガしません。 詳細については、DOM Level 3 Eventsを参照してください。 指定されない場合、useCaptureはデフォルトのfalseを適用します。 注意: useCaptureは主要なブラウザの最近のバージョン、またはそれ以上でのみ任意(optional)になっています。 そのため、例えばFirefox 6より前のバージョンでは任意ではないため、この引数を指定する必要があります。 |
[wantsUntrusted] (Mozilla、Firefoxのみ) |
型: もしtrueが指定されると、リスナーはWebコンテンツによって送信された作り物のイベントを受け取ります。 (デフォルト値はChromeではfalseで、通常のWebページではtrueです。) この引数はGeckoでのみ利用可能で、主にアドオンのコード用、ブラウザ自身に有用なものです。 詳細は、特権ページと非特権ページとのやり取りのページを参照してください。 |
サンプル
シンプルなリスナーの登録
下記の例ではmodifyText()
は、
addEventListener()
を使用してクリックイベントをリスナーに登録しています。
テーブルの何処かをクリックすると、ハンドラがバブルアップしてmodifyText()
を実行します。
もし、リスナー関数に引数を渡したいのであれば、無名関数を使用することが出来ます。
<!DOCTYPE html>
<html>
<head>
<style></style>
</head>
<body>
<table id="outside">
<tr><td id="t1">one</td></tr>
<tr><td id="t2">two</td></tr>
</table>
<script>
// t2の内容を変更する関数
function modifyText() {
var t2 = document.getElementById("t2");
if (t2.firstChild.nodeValue == "three") {
t2.firstChild.nodeValue = "two";
} else {
t2.firstChild.nodeValue = "three";
}
}
// tへ、イベントリスナー追加
var el = document.getElementById("outside");
el.addEventListener("click", modifyText, false);
</script>
</body>
</html>
無名関数を使用したイベントリスナー
<!DOCTYPE html>
<html>
<head>
<style></style>
</head>
<body>
<table id="outside">
<tr><td id="t1">one</td></tr>
<tr><td id="t2">two</td></tr>
</table>
<script>
// t2の内容を変更する関数
function modifyText(new_text) {
var t2 = document.getElementById("t2");
t2.firstChild.nodeValue = new_text;
}
// テーブルのイベントリスナーへ関数を追加
var el = document.getElementById("outside");
el.addEventListener("click", function(){modifyText("four")}, false);
</script>
</body>
</html>
注意事項
何故、addEventListenerを使用するのか?
addEventListener
は、指定したDOM(W3Cの)内にイベントリスナーとして登録する方法です。
これを使用するメリットは下記の通りです。
- イベントに複数のハンドラを追加することが可能です。 これは特に他のライブラリ/拡張が使用されていた場合であっても、 DHTMLライブラリまたはMozilla拡張で問題なく動作させる必要がある際に便利です。
- リスナーが稼働する際(capturing vs bubbling)に、きめ細かく制御することを可能にしてくれます。
- HTMLの要素では無いDOM要素でも動作します。
古い方式でのイベントリスナー登録については後述します。
イベント送信中のリスナー追加について
もし、イベント処理中にEventListener
がEventTarget
に追加されると、
それは現在のアクションによってトリガされませんが、バブリングフェーズのようなその後のイベントフロー段階でトリガーされるかもしれません。
複数の同一イベントリスナーについて
もし、複数の同一EventListeners
が、同じパラメータで同じEventTarget
に登録されると、
重複されたインスタンスが破棄されます。
2度EventListener
呼び出しが発生させられることは無く、重複したものは破棄されるため、
removeEventListenerを使用して手動で削除する必要はありません。
ハンドラ内でのthisの値について
イベントハンドラの関数内から、その発火元の要素を参照したくなる事がよくあります。
addEventListener()
を使用して、関数を割り当てたのであれば、
呼び出し元への参照がthis
の値となって関数内に渡されます。
上記の例であれば、modifyText()
内のthis
の値は、
クリックイベントから呼び出されたのであれば、テーブル't'への参照になります。
比較として、仮にHTML内にハンドラが次のように配置されていた場合、
<table id="t" onclick="modifyText();">
. . .
onclickイベントで呼び出された際の、modifyText()内のthis
の値は、
グローバル(window)オブジェクトへの参照になります。
注意: JavaScript 1.8.5で導入されたFunction.prototype.bind()
メソッドでは、
与えられた関数が呼ばれる全ての状況で、this
として使用されるべき値を指定させてくれます。
これは、関数が呼び出される際にコンテキストに依存してthis
がはっきりしない問題を容易に解決させてくれます。
ただし、後でそれを削除することが出来るように、そのリスナーへの参照を保持しておく必要があります。
下記は、bind
有りと無しの例です。
var Something = function(element) {
this.name = 'Something Good';
this.onclick1 = function(event) {
// thisはクリックされた要素を指してしまうので、undefined
console.log(this.name);
};
this.onclick2 = function(event) {
//このオブジェクト自身にbindされたので、'Something Good'
console.log(this.name);
};
//bind無し
element.addEventListener('click', this.onclick1, false);
//bind有り
element.addEventListener('click', this.onclick2.bind(this), false);
}
上記の例の問題は、bindされたリスナーを削除することが出来ない事です。
別の解決方法として、handleEvent
と呼ばれる特別な関数を使用してイベントをキャッチする方法があります。
var Something = function(element) {
this.name = 'Something Good';
this.handleEvent = function(event) {
// thisはこのSomethingオブジェクトとなるので、'Something Good'
console.log(this.name);
switch(event.type) {
case 'click':
// クリック時の何らかの処理…
break;
case 'dblclick':
// ダブルクリック時の何らかの処理…
break;
}
};
// このケースでのリスナーは、this.handleEventでは無く、
// thisです。
element.addEventListener('click', this, false);
element.addEventListener('dblclick', this, false);
// 適切にリスナーを削除することが可能です。
element.removeEventListener('click', this, false);
element.removeEventListener('dblclick', this, false);
}
古いIEとattachEventについて
IE9より前のバージョンのIEでは、標準のaddEventListener
の代わりに
attachEventを使用します。
IEをサポートするには、上記の例を下記のように修正します。
if (el.addEventListener) {
el.addEventListener('click', modifyText, false);
} else if (el.attachEvent) {
el.attachEvent('onclick', modifyText);
}
ただしattachEventは面倒なことに、this
の値はイベントを起こした要素ではなく、
window
オブジェクトへの参照になってしまいます。
互換性への対処
IE8でサポートされないaddEventListener
、removeEventListener
、
Event.preventDefault
、Event.stopPropagation
を下記のコードを使用して、
あなたのスクリプト内で代替手段を用いることが可能です。
このコードは、handleEvent
とDOMContentLoaded
の使用をサポートします。
注意: IE8でサポートされないuseCapture
の代替手段は存在しません。
下記のコードは、IE8のみをサポートするコードであることにも注意してください。
(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 (listener.handleEvent) {
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);
}
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() {
// ... 処理 ...
};
この方法は、もし既に他の既存のクリックイベントのリスナーがあると、それを置き換えてしまいます。 同様に、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(e){
/* 処理 */
}, false);
}
// ケース:2
function processEvent(e){
/* 処理 */
}
for(i=0 ; i<els.length ; i++){
els[i].addEventListener("click", processEvent, false);
}
ケース:1では、新しい(無名)関数がループの度に作成されます。
ケース:2では、先に宣言した同じ関数がイベントハンドラとして使用され、結果としてメモリ消費を抑えることが出来ます。
更にケース:1では、無名関数への参照を保持できないため、そのハンドラへの参照を持つことが出来ず、
element.removeEventListenerを呼び出すことが不可能になります。
ケース:2では、myElement.removeEventListener("click", processEvent, false)
とすれば、
それを行うことが可能です。
ブラウザの互換性
機能 | Chrome | Firefox (Gecko) |
IE | Opera | Safari |
---|---|---|---|---|---|
基本 | 1.0 | 1.0 (1.7 or earlier) | 9.0 | 7 | 1.0 |
useCapture指定が 任意 |
1.0 | 6.0 | 9.0 | 11.6 | ◯ |
機能 | Android | Firefox Mobile |
IE Mobile |
Opera Mobile |
Safari Mobile |
|
---|---|---|---|---|---|---|
基本 | 1.0 | 1.0 (1.0) | 9.0 | 6.0 | 1.0 | |
useCapture指定が 任意 |
? | ? | ? | ? | ? |
Geckoでの注意事項
-
Firefox 6より前のバージョンでは、もし
useCapture
引数に明示的にfalse
が指定されていなければ、 例外がスローされます。 Gecko 9.0(Firefox 9.0 / Thunderbird 9.0 / SeaMonkey 2.6)より前のバージョンでは、 addEventListener()はリスナーの引数がnull
だと例外をスローしますが、 現在ではメソッドはエラーをエラーを返さず、何も行いません。
Webkitでの注意事項
-
Webkitで
useCapture
引数が明示的に省略可になったのは2011年6月ですが、 それ以前から動作していました。 この変更は、Safari5.1とChrome13で実装されました。
関連項目
仕様
© 2017 Mozilla Contributors
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
このページは、ページトップのURL先のMozilla Developer Network(以下、MDN)のコンテンツを翻訳した内容を基に構成されています。 構成について異なる点も含まれますので、下記の項目を確認し、必要に応じて元のコンテンツをご確認ください。 もし、誤訳などの間違いを見つけましたら、 @tomofまで教えていただければ幸いです。
- 特定のブラウザに特化しすぎている情報やあまりにも古い情報、 または試験的に導入されているようなAPIや機能については、省略していることがあります。
- 例やデモについて、実際にページ内で動作させる関係で一部ソースコードを変更している場合や、 その例で使用しているコンテンツの単語や文章などを日本人向けに変更しいてる場合があります。
- MDNの更新頻度が高いため、元のコンテンツと比べ情報が古くなっている可能性があります。
- "訳注:"などの断わりを入れた上で、日本人向けの情報の追記を行っている事があります。