From 586b39e7a70f908cfe044af4232a52ded34ea65b Mon Sep 17 00:00:00 2001 From: Masahiro FUJIMOTO Date: Sun, 30 Jan 2022 10:53:48 +0900 Subject: EventTarget インターフェイスの文書を移行 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/eventtarget/addeventlistener/index.html | 785 --------------------- .../web/api/eventtarget/addeventlistener/index.md | 785 +++++++++++++++++++++ .../web/api/eventtarget/dispatchevent/index.html | 42 -- .../ja/web/api/eventtarget/dispatchevent/index.md | 42 ++ .../ja/web/api/eventtarget/eventtarget/index.html | 74 -- files/ja/web/api/eventtarget/eventtarget/index.md | 74 ++ files/ja/web/api/eventtarget/index.html | 122 ---- files/ja/web/api/eventtarget/index.md | 122 ++++ .../api/eventtarget/removeeventlistener/index.html | 220 ------ .../api/eventtarget/removeeventlistener/index.md | 220 ++++++ 10 files changed, 1243 insertions(+), 1243 deletions(-) delete mode 100644 files/ja/web/api/eventtarget/addeventlistener/index.html create mode 100644 files/ja/web/api/eventtarget/addeventlistener/index.md delete mode 100644 files/ja/web/api/eventtarget/dispatchevent/index.html create mode 100644 files/ja/web/api/eventtarget/dispatchevent/index.md delete mode 100644 files/ja/web/api/eventtarget/eventtarget/index.html create mode 100644 files/ja/web/api/eventtarget/eventtarget/index.md delete mode 100644 files/ja/web/api/eventtarget/index.html create mode 100644 files/ja/web/api/eventtarget/index.md delete mode 100644 files/ja/web/api/eventtarget/removeeventlistener/index.html create mode 100644 files/ja/web/api/eventtarget/removeeventlistener/index.md diff --git a/files/ja/web/api/eventtarget/addeventlistener/index.html b/files/ja/web/api/eventtarget/addeventlistener/index.html deleted file mode 100644 index 30d9148491..0000000000 --- a/files/ja/web/api/eventtarget/addeventlistener/index.html +++ /dev/null @@ -1,785 +0,0 @@ ---- -title: EventTarget.addEventListener() -slug: Web/API/EventTarget/addEventListener -tags: - - API - - AccessOuterData - - DOM - - Detecting Events - - Event Handlers - - Event Listener - - EventTarget - - JavaScript - - Method - - PassingData - - Receiving Events - - Reference - - addEventListener - - attachEvent - - events - - mselementresize -translation_of: Web/API/EventTarget/addEventListener ---- -

{{APIRef("DOM Events")}}

- -

{{domxref("EventTarget")}} の addEventListener() メソッドは、特定のイベントが対象に配信されるたびに呼び出される関数を設定します。 対象としてよくあるものは {{domxref("Element")}}, {{domxref("Document")}}, {{domxref("Window")}} ですが、イベントに対応したあらゆるオブジェクトが対象になることができます ({{domxref("XMLHttpRequest")}} など)。

- -

addEventListener() は関数または {{domxref("EventListener")}} を実装したオブジェクトを、呼び出される {{domxref("EventTarget")}} における指定されたイベント種別のイベントリスナーのリストに加えることで動作します。

- -

構文

- -
target.addEventListener(type, listener [, options]);
-target.addEventListener(type, listener [, useCapture]);
-target.addEventListener(type, listener [, useCapture, wantsUntrusted {{Non-standard_inline}}]); // Gecko/Mozilla only
- -

引数

- -
-
type
-
対象とするイベントの種類を表す文字列
-
listener
-
指定された型のイベントが発生するときに通知 ({{domxref("Event")}} インターフェースを実装しているオブジェクト) を受け取るオブジェクト。これは、 {{domxref("EventListener")}} インタフェースを実装するオブジェクト、あるいは、単純に、JavaScript の関数でなければなりません。コールバックについて詳しくは、{{anch("The event listener callback", "イベントリスナーのコールバック")}}を参照してください。
-
options {{optional_inline}}
-
対象のイベントリスナーの特性を指定する、オプションのオブジェクトです。次のオプションが使用できます。 -
-
capture
-
{{jsxref("Boolean")}} 値で、この型のイベントが DOM ツリーで下に位置する EventTarget配信 (dispatch) される前に、登録された listener に配信されることを示します。
-
once
-
{{jsxref("Boolean")}} 値で、 listener の呼び出しを一回のみのとしたいかどうかを値で指定します。 true を指定すると、 listener は一度実行された時に自動的に削除されます。
-
passive
-
{{jsxref("Boolean")}} 値で、 true ならば、 listener で指定された関数が {{domxref("Event.preventDefault", "preventDefault()")}} を呼び出さないことを示します。呼び出されたリスナーが preventDefault() を呼び出すと、ユーザーエージェントは何もせず、コンソールに警告を出力します。詳細は{{anch("Improving scrolling performance with passive listeners", "パッシブリスナーによるスクロール性能の改善")}}をご覧ください。
-
{{non-standard_inline}} mozSystemGroup
-
{{jsxref("Boolean")}} 値で、リスナーをシステムグループに追加するべきであることを示します。コードが XBL または Firefox ブラウザーの {{glossary("chrome")}} で実行されている場合のみ利用できます。
-
-
-
useCapture {{optional_inline}}
-
{{jsxref("Boolean")}} 値で、この型のイベントが、DOM ツリー内の下の EventTarget に配信される前に、登録された listener に配信されるかどうかを示します。ツリーを上方向にバブリングしているイベントは、キャプチャーを使用するように指定されたリスナーを起動しません。イベントのバブリングとキャプチャーは、両方の要素がそのイベントのハンドラーを登録している場合に、別の要素内に入れ子になっている要素で発生するイベントを伝播する 2 つの方法です。イベント伝播モードは、要素がイベントを受け取る順番を決定します。詳細な説明は DOM Level 3 EventsJavaScript Event order を参照してください。指定されていない場合、 useCapture は既定で false となります。
-
-
注: イベントターゲットに登録されたイベントリスナーは、捕捉フェーズやバブリングフェーズではなく、ターゲットフェーズのイベントになります。ターゲットフェーズのイベントは、useCapture 引数にかかわらず、すべてのリスナーを追加された順序で実行します。
- -
注: useCapture はどんなブラウザーでもオプションになっているわけではありません。完全で最大限の互換性を得たいなら、引数を指定するようにしてください。
-
-
wantsUntrusted {{Non-standard_inline}}
-
true の場合、このリスナーはウェブコンテンツによって発火された合成イベント (カスタムイベント) を受け取ります (ブラウザーの{{glossary("chrome", "クローム")}}では既定で false ですが、一般のウェブページでは true です)。この引数は Gecko でのみ利用可能であり、主にアドオンやブラウザー自身の役に立つものです。
-
- -

返値

- -

undefined

- -

使用方法のメモ

- -

イベントリスナーのコールバック

- -

イベントリスナーには、コールバック関数を指定することもできますが、 {{domxref("EventListener")}} を実装したオブジェクトを指定することもでき、その場合は {{domxref("EventListener.handleEvent()", "handleEvent()")}} メソッドがコールバック関数として機能します。

- -

コールバック関数自体は、 handleEvent() メソッドと同じ引数と返値を持ちます。つまり、コールバック関数は発生したイベントを説明する {{domxref("Event")}} に基づいたオブジェクトを唯一の引数として受け付け、何も返しません。

- -

たとえば、次のイベントハンドラーコールバックは、 {{domxref("Element/fullscreenchange_event", "fullscreenchange")}} および {{domxref("Element/fullscreenerror_event", "fullscreenerror")}} の両方を処理するために使用することができます。

- -
function eventHandler(event) {
-  if (event.type == 'fullscreenchange') {
-    /* handle a full screen toggle */
-  } else /* fullscreenerror */ {
-    /* handle a full screen toggle error */
-  }
-}
- -

オプションの対応の安全な検出

- -

DOM 仕様書の古い版では、 addEventListener() の第 3 引数はキャプチャーを使用するかどうかを示す論理値でした。時間の経過とともに、より多くのオプションが必要であることが明らかになりました。関数にさらに多くの引数を追加する (オプションの値を扱うときに非常に複雑になります) のではなく、第 3 引数は、イベントリスナーを削除する過程を設定するためのオプションの値を定義するさまざまなプロパティを含むことができるオブジェクトに変更されました。

- -

古いブラウザーは (あまり古くないブラウザーも含めて) 第 3 引数がまだ論理であると仮定しているので、このシナリオをインテリジェントに処理できるようにコードを構築する必要があります。これを行うには、興味のあるオプションごとに機能検出を使用します。

- -

例えば、 passive オプションをチェックしたい場合は次のようにします。

- -
let passiveSupported = false;
-
-try {
-  const options = {
-    get passive() { // この関数はブラウザーが passive プロパティに
-                    // アクセスしようとしたときに呼び出されます。
-      passiveSupported = true;
-      return false;
-    }
-  };
-
-  window.addEventListener("test", null, options);
-  window.removeEventListener("test", null, options);
-} catch(err) {
-  passiveSupported = false;
-}
-
- -

これは、 options オブジェクトを生成し、 passive プロパティのゲッター関数を持たせます。ゲッターは、呼ばれた場合に passiveSupported フラグを true に設定します。つまり、ブラウザーが passive プロパティの値を options オブジェクトでチェックした場合、 passiveSupportedtrue に設定され、そうでなければ false のままになります。次に addEventListener() を呼び出して、これらのオプションを指定して偽のイベント・ハンドラーをセットアップし、ブラウザーが第 3 引数としてオブジェクトを認識した場合にオプションがチェックされるようにします。その後、 removeEventListener() を呼び出して、自分たちで後始末をします。 (呼ばれていないイベントリスナーでは handleEvent() は無視されることに注意してください。)

- -

この方法で、任意のオプションに対応しているかどうかを確認することができます。上に示したようなコードを使って、そのオプションのゲッターを追加するだけです。

- -

そして、問題のオプションを使用する実際のイベントリスナーを作成したい場合は、次のようにします。

- -
someElement.addEventListener("mouseup", handleMouseUp, passiveSupported
-                               ? { passive: true } : false);
- -

ここでは、 {{domxref("Element/mouseup_event", "mouseup")}} イベントのリスナーを someElement 要素に追加しています。第 3 引数の passiveSupportedtrue である場合、 options オブジェクトを passivetrue に設定して指定しています。そうでない場合は、論理値を渡す必要があることがわかっているので、 useCapture 引数の値として false を渡しています。

- -

ご希望であれば、 ModernizrDetect It のようなサードパーティ製のライブラリを使用してこのテストを行うことができます。

- -

Web Incubator Community GroupEventListenerOptions の記事を参考にしてください。

- -

- -

シンプルなリスナーの追加

- -

この例は、要素上でのマウスクリックを監視するための addEventListener() の使い方を紹介します。

- -

HTML

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

JavaScript

- -
// t2 のコンテンツを変更する関数
-function modifyText() {
-  const t2 = document.getElementById("t2");
-  if (t2.firstChild.nodeValue == "three") {
-    t2.firstChild.nodeValue = "two";
-  } else {
-    t2.firstChild.nodeValue = "three";
-  }
-}
-
-// イベントリスナーを table に追加
-const el = document.getElementById("outside");
-el.addEventListener("click", modifyText, false);
-
- -

このコードの中で、 modifyText()addEventListener() を使用して登録された click イベントのリスナーです。表の中のどこかをクリックすると、ハンドラーに上がり、 modifyText() を実行します。

- -

結果

- -

{{EmbedLiveSample('Add_a_simple_listener')}}

- -

無名関数を使用したイベントリスナー

- -

ここで、無名関数を使用してイベントリスナーに引数を渡す方法を見てみましょう。

- -

HTML

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

JavaScript

- -
// t2 のコンテンツを変更する関数
-function modifyText(new_text) {
-  const t2 = document.getElementById("t2");
-  t2.firstChild.nodeValue = new_text;
-}
-
-// イベントリスナーを table に追加する関数
-const el = document.getElementById("outside");
-el.addEventListener("click", function(){modifyText("four")}, false);
-
- -

なお、リスナーは実際にイベントに応答する modifyText() 関数に引数を送信することができるコードをカプセル化している無名関数であることに注意してください。

- -

結果

- -

{{EmbedLiveSample('Event_listener_with_anonymous_function')}}

- -

アロー関数を使用したイベントリスナー

- -

この例はアロー関数表記を使用して実装された、簡単なイベントリスナーを紹介しています。

- -

HTML

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

JavaScript

- -
// t2 の中身を変更するための関数
-function modifyText(new_text) {
-  const t2 = document.getElementById("t2");
-  t2.firstChild.nodeValue = new_text;
-}
-
-// アロー関数で table にイベントリスナーを追加
-const el = document.getElementById("outside");
-el.addEventListener("click", () => { modifyText("four"); }, false);
-
- -

結果

- -

{{EmbedLiveSample('Event_listener_with_an_arrow_function')}}

- -

なお、無名関数とアロー関数は似ており、違いは this のバインドです。無名関数 (及び伝統的なすべての JavaScript 関数) は自身の this を作成するのに対し、アロー関数はそれを含む関数の this を継承します。

- -

つまり、アロー関数を使用したときは、それを含む関数の変数や定数をイベントハンドラーで利用することができます。

- -

Example of options usage

- -

HTML

- -
<div class="outer">
-  outer, once & none-once
-  <div class="middle" target="_blank">
-    middle, capture & none-capture
-    <a class="inner1" href="https://www.mozilla.org" target="_blank">
-      inner1, passive & preventDefault(which is not allowed)
-    </a>
-    <a class="inner2" href="/" target="_blank">
-      inner2, none-passive & preventDefault(not open new page)
-    </a>
-  </div>
-</div>
-
- -

CSS

- -
.outer, .middle, .inner1, .inner2 {
-  display: block;
-  width:   520px;
-  padding: 15px;
-  margin:  15px;
-  text-decoration: none;
-}
-.outer {
-  border: 1px solid red;
-  color:  red;
-}
-.middle {
-  border: 1px solid green;
-  color:  green;
-  width:  460px;
-}
-.inner1, .inner2 {
-  border: 1px solid purple;
-  color:  purple;
-  width:  400px;
-}
-
- -

JavaScript

- -
const outer  = document.querySelector('.outer');
-const middle = document.querySelector('.middle');
-const inner1 = document.querySelector('.inner1');
-const inner2 = document.querySelector('.inner2');
-
-const capture = {
-  capture : true
-};
-const noneCapture = {
-  capture : false
-};
-const once = {
-  once : true
-};
-const noneOnce = {
-  once : false
-};
-const passive = {
-  passive : true
-};
-const nonePassive = {
-  passive : false
-};
-
-outer.addEventListener('click', onceHandler, once);
-outer.addEventListener('click', noneOnceHandler, noneOnce);
-middle.addEventListener('click', captureHandler, capture);
-middle.addEventListener('click', noneCaptureHandler, noneCapture);
-inner1.addEventListener('click', passiveHandler, passive);
-inner2.addEventListener('click', nonePassiveHandler, nonePassive);
-
-function onceHandler(event) {
-  alert('outer, once');
-}
-function noneOnceHandler(event) {
-  alert('outer, none-once, default');
-}
-function captureHandler(event) {
-  //event.stopImmediatePropagation();
-  alert('middle, capture');
-}
-function noneCaptureHandler(event) {
-  alert('middle, none-capture, default');
-}
-function passiveHandler(event) {
-  // Unable to preventDefault inside passive event listener invocation.
-  event.preventDefault();
-  alert('inner1, passive, open new page');
-}
-function nonePassiveHandler(event) {
-  event.preventDefault();
-  //event.stopPropagation();
-  alert('inner2, none-passive, default, not open new page');
-}
-
- -

結果

- -

外側、中央、内側のコンテナーをそれぞれクリックして、オプションがどのように動作するかを確認してください。

- -

{{ EmbedLiveSample('Example_of_options_usage', 600, 310, '', 'Web/API/EventTarget/addEventListener') }}

- -

options オブジェクトで特定の値を使用する前に、ユーザーのブラウザーがそれに対応していることを確認するのが良いでしょう。詳細は{{anch("Safely detecting option support", "オプションの対応の安全な検出")}}を参照してください。

- -

その他の注

- -

なぜ addEventListener() を使うのか

- -

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

- - - -

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

- -

イベント配信中のリスナーの追加

- -

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

- -

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

- -

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

- -

ただし、無名関数をハンドラーとして使用する場合、そのようなリスナーは同じにはならないことに注意してください。無名関数はループ内であっても繰り返し呼び出されるだけで、同じソースコードを使って定義されていても同じにはならないためです。

- -

ただし、このような場合に同じ名前の関数を繰り返し定義することは、より問題になる可能性があります (後述のメモリの問題を参照してください)。

- -

ハンドラー内での "this" の値

- -

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

- -

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

- -
my_element.addEventListener('click', function (e) {
-  console.log(this.className)           // logs the className of my_element
-  console.log(e.currentTarget === this) // logs `true`
-})
-
- -

アロー関数は独自の this コンテキストを持たないことをお忘れなく。

- -
my_element.addEventListener('click', (e) => {
-  console.log(this.className)           // WARNING: `this` is not `my_element`
-  console.log(e.currentTarget === this) // logs `false`
-})
- -

イベントハンドラー (例えば {{domxref("GlobalEventHandlers.onclick", "onclick")}}) が HTML ソース内の要素に指定されていた場合、属性値の Javascirpt コードは、 addEventListener() を使用するような方法で this の値をバインドしたハンドラー関数に置き換えられます。コード内に this が現れた場合には、要素への参照を表します。

- -
<table id="my_table" onclick="console.log(this.id);"><!-- `this` refers to the table; logs 'my_table' -->
-  ...
-</table>
-
- -

this の値は、属性値の中のコードによって呼び出される関数内では、標準的な規則に従って振る舞うことに注意してください。これは次の例で示されています。

- -
<script>
-  function logID() { console.log(this.id); }
-</script>
-<table id="my_table" onclick="logID();"><!-- when called, `this` will refer to the global object -->
-  ...
-</table>
-
- -

thislogID() 内においては、グローバルオブジェクト {{domxref("Window")}} (または厳格モードの場合は undefinedになります。

- -

bind() を使用した this の指定

- -

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

- -

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

- -
const Something = function(element) {
-  // |this| is a newly created object
-  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); // これが仕掛けです
-}
-const s = new Something(document.body);
-
- -

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

- -
const Something = function(element) {
-  // |this| is a newly created object
-  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);
-}
-const s = new Something(document.body);
-
- -

this の参照を扱うためのもう一つの方法は、 EventListener にアクセスする必要のあるフィールドを含むオブジェクトのメソッドを呼び出す関数を渡すことです。

- -
class SomeClass {
-
-  constructor() {
-    this.name = 'Something Good';
-  }
-
-  register() {
-    const that = this;
-    window.addEventListener('keydown', function(e) { that.someMethod(e); });
-  }
-
-  someMethod(e) {
-    console.log(this.name);
-    switch(e.keyCode) {
-      case 5:
-        // some code here...
-        break;
-      case 6:
-        // some code here...
-        break;
-    }
-  }
-
-}
-
-const myObject = new SomeClass();
-myObject.register();
- -

イベントリスナーのデータの出し入れ

- -

イベントリスナーは島のようなもので、それらにデータを渡すのは非常に難しく、ましてや実行後にそれらからデータを取り出すのは非常に難しいと思われるかもしれません。イベントリスナーは、イベントオブジェクトという1つの引数を取るだけで、それは自動的にリスナーに渡され、返値が無視されるからです。では、どのようにしてデータを渡したり、取り出したりすることができるのでしょうか?これを行うための良い方法がいくつかあります。

- -

"this" を使用したイベントリスナーへのデータの入力

- -

前述の通り、 Function.prototype.bind() を使用すると this 参照変数を通じてイベントリスナーに値を渡すことができます。

- -
const myButton = document.getElementById('my-button-id');
-const someString = 'Data';
-
-myButton.addEventListener('click', function () {
-  console.log(this);  // Expected Value: 'Data'
-}.bind(someString));
-
- -

この方法は、イベントリスナーの中からプログラムでイベントリスナーがどの HTML 要素で発生したかを知る必要がない場合に適しています。これを行う主な利点は、実際に引数リストにデータを渡す場合とほぼ同じ方法でイベントリスナーがデータを受け取ることです。

- -

外部スコープのプロパティを使用したイベントリスナーへのデータの入力

- -

外部スコープに (const, let を付けた) 変数宣言が含まれている場合、そのスコープで宣言されたすべての内部関数はその変数にアクセスすることができます(外部関数/内部関数についてはこちらを、変数スコープについてはこちらを参照してください)。したがって、イベントリスナーの外部からデータにアクセスする最も簡単な方法の1つは、イベントリスナーが宣言されているスコープにアクセスできるようにすることです。

- -
const myButton = document.getElementById('my-button-id');
-const someString = 'Data';
-
-myButton.addEventListener('click', function() {
-  console.log(someString);  // Expected Value: 'Data'
-
-  someString = 'Data Again';
-});
-
-console.log(someString);  // Expected Value: 'Data' (will never output 'Data Again')
-
- -
-

注: 内側のスコープは外側のスコープにある const, let 変数にアクセスすることができますが、イベントリスナーの定義後に、同じ外側のスコープ内でこれらの変数にアクセスできるようになることは期待できません。なぜでしょうか?単純に、イベントリスナーが実行される頃には、イベントリスナーが定義されたスコープは既に実行を終了しているからです。

-
- -

オブジェクトを用いたイベントリスナーのデータの出し入れ

- -

JavaScript のほとんどの関数とは異なり、オブジェクトはそのオブジェクトを参照する変数がメモリ内に存在する限り、メモリ内に保持されます。それに加えて、オブジェクトはプロパティを持つことができ、参照によって渡すことができることから、スコープ間でデータを共有するための有力な候補となります。これについて調べてみましょう。

- -
-

注: JavaScript の関数は厳密にはオブジェクトです。 (そのため、プロパティを持つことができ、メモリ内に永続的に存在する変数に代入されていれば、実行終了後もメモリ内に保持されます。)

-
- -

オブジェクトを参照する変数がメモリに存在する限り、オブジェクトのプロパティを使用してメモリにデータを格納することができるので、実際にそれらを使用して、イベントリスナーにデータを渡し、イベントハンドラーが実行された後でデータに変更があった場合には、それを戻すことができます。この例を考えてみましょう。

- -
const myButton = document.getElementById('my-button-id');
-const someObject = {aProperty: 'Data'};
-
-myButton.addEventListener('click', function() {
-  console.log(someObject.aProperty);  // Expected Value: 'Data'
-
-  someObject.aProperty = 'Data Again';  // Change the value
-});
-
-window.setInterval(function() {
-  if (someObject.aProperty === 'Data Again') {
-    console.log('Data Again: True');
-    someObject.aProperty = 'Data';  // Reset value to wait for next event execution
-  }
-}, 5000);
-
- -

この例では、イベントリスナーとインターバル関数の両方が定義されているスコープは、 someObject.aProperty の元の値が変更される前に実行を終了していたとしても、イベントリスナーとインターバル関数の両方で someObject がメモリ内に (参照によって) 持続するため、両方とも同じデータにアクセスできます (つまり、一方がデータを変更したときに、もう一方がその変更に対応できます)。

- -
-

注: オブジェクトは参照にで変数に格納されます。つまり、実際のデータのメモリの場所だけが変数に格納されます。とりわけ、これはオブジェクトを「格納」する変数が、実際に同じオブジェクト参照が代入 (「格納」) されている他の変数に影響を与えることができるということです。2つの変数が同じオブジェクトを参照している場合 (例えば、 let a = b = {aProperty: 'Yeah'};)、どちらかから変数のデータを変更すると、もう一方の変数に影響を与えます。

-
- -
-

注: オブジェクトは参照によって変数に格納されているので、関数の実行を停止した後も、関数からオブジェクトを返す (データを失わないようにメモリに保存しておく) ことができます。

-
- -

古い Internet Explorer と attachEvent

- -

IE9 より前の Internet Explorer では、標準の addEventListener ではなく、 {{domxref("EventTarget.attachEvent", "attachEvent()")}} を使わなければなりません。 IE に対応するためには、上記の例を以下のように修正しなけれなりません。

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

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

- -

attachEvent() メソッドは、ウェブページの特定の要素がサイズ変更されたことを検出するために onresize イベントを対応付けることができました。独自の mselementresize イベントは、イベントハンドラーを登録する addEventListener メソッドによって対応付けられた場合。 onresize と同様の機能を提供し、特定の HTML 要素の寸法が変更されたときに発行されます。

- -

ポリフィル

- -

次のコードをスクリプトの初めに書いておくと、 Internet Explorer 8 では対応していない addEventListener(), removeEventListener(), {{domxref("Event.preventDefault()")}}, {{domxref("Event.stopPropagation()")}} が動作するようになります。このコードは、 handleEvent()DOMContentLoaded イベントにも対応します。

- -
-

注: useCapture に対応していないため、 IE 8 では代わりの方法はありません。以下のコードは IE 8 への対応を追加するだけです。また、 IE 8 用の代替モジュールは、標準モードのみで動作します。 doctype 宣言が必要です。

-
- -
(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)、などのような関連するイベントハンドラも同様です。

- -

これは本質的に {{glossary("DOM", "DOM 0")}} の一部であるため、イベントリスナーを追加するためのこのテクニックは非常に広く対応されており、特別なブラウザー間の互換コードを必要としません。これは、 (IE 8 以前のような) 非常に古いブラウザーに対応しなければならない場合に、イベントリスナーを動的に登録するために使用されます。 addEventListener のブラウザー対応の詳細については、下記の表を参照してください。

- -

メモリに関する問題

- -
const els = document.getElementsByTagName('*');
-
-// ケース 1
-for(let i=0 ; i < els.length; i++){
-  els[i].addEventListener("click", function(e){/*関数の処理*/}, false);
-}
-
-// ケース 2
-function processEvent(e){
-  /*関数の処理*/
-}
-
-for(let i=0 ; i < els.length; i++){
-  els[i].addEventListener("click", processEvent, false);
-}
-
- -

上記の最初のケースでは、ループが繰り返されるたびに新しい (無名の) ハンドラー関数が作成されます。 2 番目のケースでは、以前に宣言された同じ関数がイベントハンドラーとして使用され、作成されるハンドラー関数が 1 つしかないため、メモリ消費量が少なくなります。さらに、最初のケースでは、無名関数への参照が保持されないため (ここでは、ループが作成する可能性のある複数の無名関数のいずれも保持されないため)、 {{domxref("EventTarget.removeEventListener", "removeEventListener()")}} を呼び出すことができません。2つ目のケースでは、 processEvent が関数への参照なので、 myElement.removeEventListener("click", processEvent, false) を実行することが可能です。

- -

実際には、メモリ消費に関しては、関数への参照が保持されていないことが本当の問題ではなく、静的な関数への参照が保持されていないことが問題なのです。以下の問題ケースでは、どちらも関数への参照は保持されていますが、繰り返しのたびに再定義されているため、静的なものではありません。 3 つ目のケースでは、無名関数の参照が反復のたびに再割り当てされています。 4 番目のケースでは、関数の定義全体は不変ですが、 (コンパイラによって[[昇格]]されていない限り) 新しいものとして繰り返し定義されているので、静的ではありません。したがって、単純に[[複数の同一のイベントリスナー]]のように見えますが、どちらの場合も、各反復処理では、ハンドラー関数への独自の参照を持つ新しいリスナーが作成されます。しかし、関数の定義自体は変更されないので、重複するリスナーごとに同じ関数が呼び出される可能性があります (特にコードが最適化されている場合)。

- -

また、どちらの場合も、関数への参照は保持されていたが、追加するごとに繰り返し再定義されていたので、上からの remove 文でリスナーを削除することができますが、最後に追加されたものだけが削除されるようになります。

- -
// For illustration only: Note "MISTAKE" of [j] for [i] thus causing desired events to all attach to SAME element
-
-// ケース 3
-for(let i=0, j=0 ; i<els.length ; i++){
-  /* do lots of stuff with j */
-  els[j].addEventListener("click", processEvent = function(e){/*do something*/}, false);
-}
-
-// ケース 4
-for(let i=0, j=0 ; i<els.length ; i++){
-  /* do lots of stuff with j */
-  function processEvent(e){/*do something*/};
-  els[j].addEventListener("click", processEvent, false);
-}
- -

パッシブリスナーを用いたスクロールの性能改善

- -

仕様書によれば、 passive オプションの既定値は常に false です。しかし、これは特定のタッチイベントを扱うイベントリスナーが (特に) スクロールを処理しようとしている間にブラウザーのメインスレッドをブロックする可能性をもたらしており、スクロール処理中の性能が大幅に低下する結果になる可能性があります。

- -

この問題を防ぐために、一部のブラウザー (特に Chrome と Firefox) では、文書レベルノードである {{domxref("Window")}}, {{domxref("Document")}}, {{domxref("Document.body")}} の {{event("touchstart")}} および {{event("touchmove")}} イベントの passive オプションの既定値を true に変更しています。これにより、イベントリスナーが呼び出されなくなるため、ユーザーがスクロールしている間にページのレンダリングをブロックすることができなくなります。

- -
-

Note: この変更された動作を実装しているブラウザー (およびそれらのブラウザーのバージョン) を知りたい場合は、下記の互換性一覧表を参照してください。

-
- -

この動作は下記のように、明示的に passive の値を false に設定することで上書きできます。

- -
/* Feature detection */
-let passiveIfSupported = false;
-
-try {
-  window.addEventListener("test", null,
-    Object.defineProperty(
-      {},
-      "passive",
-      {
-        get: function() { passiveIfSupported = { passive: false }; }
-      }
-    )
-  );
-} catch(err) {}
-
-window.addEventListener('scroll', function(event) {
-  /* do something */
-  // can't use event.preventDefault();
-}, passiveIfSupported );
-
- -

addEventListener()options 引数に対応していない古いブラウザーでは、これを使用しようとすると、機能検出を適切に使用せずに useCapture 引数の使用を防ぐことがあります。

- -

基本的な {{event("scroll")}} イベントの passive の値を気にする必要はありません。キャンセルできないので、イベントリスナーはどのような場合でもページのレンダリングをブロックすることはできません。

- -

仕様書

- - - - - - - - - - - - - - - - - - - - - - - - - - -
仕様書状態備考
{{SpecName("DOM WHATWG", "#dom-eventtarget-addeventlistener", "EventTarget.addEventListener()")}}{{Spec2("DOM WHATWG")}}
{{SpecName("DOM4", "#dom-eventtarget-addeventlistener", "EventTarget.addEventListener()")}}{{Spec2("DOM4")}}
{{SpecName("DOM2 Events", "#Events-EventTarget-addEventListener", "EventTarget.addEventListener()")}}{{Spec2("DOM2 Events")}}初回定義
- -

ブラウザーの互換性

- -

{{Compat("api.EventTarget.addEventListener", 3)}}

- -

関連情報

- - diff --git a/files/ja/web/api/eventtarget/addeventlistener/index.md b/files/ja/web/api/eventtarget/addeventlistener/index.md new file mode 100644 index 0000000000..30d9148491 --- /dev/null +++ b/files/ja/web/api/eventtarget/addeventlistener/index.md @@ -0,0 +1,785 @@ +--- +title: EventTarget.addEventListener() +slug: Web/API/EventTarget/addEventListener +tags: + - API + - AccessOuterData + - DOM + - Detecting Events + - Event Handlers + - Event Listener + - EventTarget + - JavaScript + - Method + - PassingData + - Receiving Events + - Reference + - addEventListener + - attachEvent + - events + - mselementresize +translation_of: Web/API/EventTarget/addEventListener +--- +

{{APIRef("DOM Events")}}

+ +

{{domxref("EventTarget")}} の addEventListener() メソッドは、特定のイベントが対象に配信されるたびに呼び出される関数を設定します。 対象としてよくあるものは {{domxref("Element")}}, {{domxref("Document")}}, {{domxref("Window")}} ですが、イベントに対応したあらゆるオブジェクトが対象になることができます ({{domxref("XMLHttpRequest")}} など)。

+ +

addEventListener() は関数または {{domxref("EventListener")}} を実装したオブジェクトを、呼び出される {{domxref("EventTarget")}} における指定されたイベント種別のイベントリスナーのリストに加えることで動作します。

+ +

構文

+ +
target.addEventListener(type, listener [, options]);
+target.addEventListener(type, listener [, useCapture]);
+target.addEventListener(type, listener [, useCapture, wantsUntrusted {{Non-standard_inline}}]); // Gecko/Mozilla only
+ +

引数

+ +
+
type
+
対象とするイベントの種類を表す文字列
+
listener
+
指定された型のイベントが発生するときに通知 ({{domxref("Event")}} インターフェースを実装しているオブジェクト) を受け取るオブジェクト。これは、 {{domxref("EventListener")}} インタフェースを実装するオブジェクト、あるいは、単純に、JavaScript の関数でなければなりません。コールバックについて詳しくは、{{anch("The event listener callback", "イベントリスナーのコールバック")}}を参照してください。
+
options {{optional_inline}}
+
対象のイベントリスナーの特性を指定する、オプションのオブジェクトです。次のオプションが使用できます。 +
+
capture
+
{{jsxref("Boolean")}} 値で、この型のイベントが DOM ツリーで下に位置する EventTarget配信 (dispatch) される前に、登録された listener に配信されることを示します。
+
once
+
{{jsxref("Boolean")}} 値で、 listener の呼び出しを一回のみのとしたいかどうかを値で指定します。 true を指定すると、 listener は一度実行された時に自動的に削除されます。
+
passive
+
{{jsxref("Boolean")}} 値で、 true ならば、 listener で指定された関数が {{domxref("Event.preventDefault", "preventDefault()")}} を呼び出さないことを示します。呼び出されたリスナーが preventDefault() を呼び出すと、ユーザーエージェントは何もせず、コンソールに警告を出力します。詳細は{{anch("Improving scrolling performance with passive listeners", "パッシブリスナーによるスクロール性能の改善")}}をご覧ください。
+
{{non-standard_inline}} mozSystemGroup
+
{{jsxref("Boolean")}} 値で、リスナーをシステムグループに追加するべきであることを示します。コードが XBL または Firefox ブラウザーの {{glossary("chrome")}} で実行されている場合のみ利用できます。
+
+
+
useCapture {{optional_inline}}
+
{{jsxref("Boolean")}} 値で、この型のイベントが、DOM ツリー内の下の EventTarget に配信される前に、登録された listener に配信されるかどうかを示します。ツリーを上方向にバブリングしているイベントは、キャプチャーを使用するように指定されたリスナーを起動しません。イベントのバブリングとキャプチャーは、両方の要素がそのイベントのハンドラーを登録している場合に、別の要素内に入れ子になっている要素で発生するイベントを伝播する 2 つの方法です。イベント伝播モードは、要素がイベントを受け取る順番を決定します。詳細な説明は DOM Level 3 EventsJavaScript Event order を参照してください。指定されていない場合、 useCapture は既定で false となります。
+
+
注: イベントターゲットに登録されたイベントリスナーは、捕捉フェーズやバブリングフェーズではなく、ターゲットフェーズのイベントになります。ターゲットフェーズのイベントは、useCapture 引数にかかわらず、すべてのリスナーを追加された順序で実行します。
+ +
注: useCapture はどんなブラウザーでもオプションになっているわけではありません。完全で最大限の互換性を得たいなら、引数を指定するようにしてください。
+
+
wantsUntrusted {{Non-standard_inline}}
+
true の場合、このリスナーはウェブコンテンツによって発火された合成イベント (カスタムイベント) を受け取ります (ブラウザーの{{glossary("chrome", "クローム")}}では既定で false ですが、一般のウェブページでは true です)。この引数は Gecko でのみ利用可能であり、主にアドオンやブラウザー自身の役に立つものです。
+
+ +

返値

+ +

undefined

+ +

使用方法のメモ

+ +

イベントリスナーのコールバック

+ +

イベントリスナーには、コールバック関数を指定することもできますが、 {{domxref("EventListener")}} を実装したオブジェクトを指定することもでき、その場合は {{domxref("EventListener.handleEvent()", "handleEvent()")}} メソッドがコールバック関数として機能します。

+ +

コールバック関数自体は、 handleEvent() メソッドと同じ引数と返値を持ちます。つまり、コールバック関数は発生したイベントを説明する {{domxref("Event")}} に基づいたオブジェクトを唯一の引数として受け付け、何も返しません。

+ +

たとえば、次のイベントハンドラーコールバックは、 {{domxref("Element/fullscreenchange_event", "fullscreenchange")}} および {{domxref("Element/fullscreenerror_event", "fullscreenerror")}} の両方を処理するために使用することができます。

+ +
function eventHandler(event) {
+  if (event.type == 'fullscreenchange') {
+    /* handle a full screen toggle */
+  } else /* fullscreenerror */ {
+    /* handle a full screen toggle error */
+  }
+}
+ +

オプションの対応の安全な検出

+ +

DOM 仕様書の古い版では、 addEventListener() の第 3 引数はキャプチャーを使用するかどうかを示す論理値でした。時間の経過とともに、より多くのオプションが必要であることが明らかになりました。関数にさらに多くの引数を追加する (オプションの値を扱うときに非常に複雑になります) のではなく、第 3 引数は、イベントリスナーを削除する過程を設定するためのオプションの値を定義するさまざまなプロパティを含むことができるオブジェクトに変更されました。

+ +

古いブラウザーは (あまり古くないブラウザーも含めて) 第 3 引数がまだ論理であると仮定しているので、このシナリオをインテリジェントに処理できるようにコードを構築する必要があります。これを行うには、興味のあるオプションごとに機能検出を使用します。

+ +

例えば、 passive オプションをチェックしたい場合は次のようにします。

+ +
let passiveSupported = false;
+
+try {
+  const options = {
+    get passive() { // この関数はブラウザーが passive プロパティに
+                    // アクセスしようとしたときに呼び出されます。
+      passiveSupported = true;
+      return false;
+    }
+  };
+
+  window.addEventListener("test", null, options);
+  window.removeEventListener("test", null, options);
+} catch(err) {
+  passiveSupported = false;
+}
+
+ +

これは、 options オブジェクトを生成し、 passive プロパティのゲッター関数を持たせます。ゲッターは、呼ばれた場合に passiveSupported フラグを true に設定します。つまり、ブラウザーが passive プロパティの値を options オブジェクトでチェックした場合、 passiveSupportedtrue に設定され、そうでなければ false のままになります。次に addEventListener() を呼び出して、これらのオプションを指定して偽のイベント・ハンドラーをセットアップし、ブラウザーが第 3 引数としてオブジェクトを認識した場合にオプションがチェックされるようにします。その後、 removeEventListener() を呼び出して、自分たちで後始末をします。 (呼ばれていないイベントリスナーでは handleEvent() は無視されることに注意してください。)

+ +

この方法で、任意のオプションに対応しているかどうかを確認することができます。上に示したようなコードを使って、そのオプションのゲッターを追加するだけです。

+ +

そして、問題のオプションを使用する実際のイベントリスナーを作成したい場合は、次のようにします。

+ +
someElement.addEventListener("mouseup", handleMouseUp, passiveSupported
+                               ? { passive: true } : false);
+ +

ここでは、 {{domxref("Element/mouseup_event", "mouseup")}} イベントのリスナーを someElement 要素に追加しています。第 3 引数の passiveSupportedtrue である場合、 options オブジェクトを passivetrue に設定して指定しています。そうでない場合は、論理値を渡す必要があることがわかっているので、 useCapture 引数の値として false を渡しています。

+ +

ご希望であれば、 ModernizrDetect It のようなサードパーティ製のライブラリを使用してこのテストを行うことができます。

+ +

Web Incubator Community GroupEventListenerOptions の記事を参考にしてください。

+ +

+ +

シンプルなリスナーの追加

+ +

この例は、要素上でのマウスクリックを監視するための addEventListener() の使い方を紹介します。

+ +

HTML

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

JavaScript

+ +
// t2 のコンテンツを変更する関数
+function modifyText() {
+  const t2 = document.getElementById("t2");
+  if (t2.firstChild.nodeValue == "three") {
+    t2.firstChild.nodeValue = "two";
+  } else {
+    t2.firstChild.nodeValue = "three";
+  }
+}
+
+// イベントリスナーを table に追加
+const el = document.getElementById("outside");
+el.addEventListener("click", modifyText, false);
+
+ +

このコードの中で、 modifyText()addEventListener() を使用して登録された click イベントのリスナーです。表の中のどこかをクリックすると、ハンドラーに上がり、 modifyText() を実行します。

+ +

結果

+ +

{{EmbedLiveSample('Add_a_simple_listener')}}

+ +

無名関数を使用したイベントリスナー

+ +

ここで、無名関数を使用してイベントリスナーに引数を渡す方法を見てみましょう。

+ +

HTML

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

JavaScript

+ +
// t2 のコンテンツを変更する関数
+function modifyText(new_text) {
+  const t2 = document.getElementById("t2");
+  t2.firstChild.nodeValue = new_text;
+}
+
+// イベントリスナーを table に追加する関数
+const el = document.getElementById("outside");
+el.addEventListener("click", function(){modifyText("four")}, false);
+
+ +

なお、リスナーは実際にイベントに応答する modifyText() 関数に引数を送信することができるコードをカプセル化している無名関数であることに注意してください。

+ +

結果

+ +

{{EmbedLiveSample('Event_listener_with_anonymous_function')}}

+ +

アロー関数を使用したイベントリスナー

+ +

この例はアロー関数表記を使用して実装された、簡単なイベントリスナーを紹介しています。

+ +

HTML

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

JavaScript

+ +
// t2 の中身を変更するための関数
+function modifyText(new_text) {
+  const t2 = document.getElementById("t2");
+  t2.firstChild.nodeValue = new_text;
+}
+
+// アロー関数で table にイベントリスナーを追加
+const el = document.getElementById("outside");
+el.addEventListener("click", () => { modifyText("four"); }, false);
+
+ +

結果

+ +

{{EmbedLiveSample('Event_listener_with_an_arrow_function')}}

+ +

なお、無名関数とアロー関数は似ており、違いは this のバインドです。無名関数 (及び伝統的なすべての JavaScript 関数) は自身の this を作成するのに対し、アロー関数はそれを含む関数の this を継承します。

+ +

つまり、アロー関数を使用したときは、それを含む関数の変数や定数をイベントハンドラーで利用することができます。

+ +

Example of options usage

+ +

HTML

+ +
<div class="outer">
+  outer, once & none-once
+  <div class="middle" target="_blank">
+    middle, capture & none-capture
+    <a class="inner1" href="https://www.mozilla.org" target="_blank">
+      inner1, passive & preventDefault(which is not allowed)
+    </a>
+    <a class="inner2" href="/" target="_blank">
+      inner2, none-passive & preventDefault(not open new page)
+    </a>
+  </div>
+</div>
+
+ +

CSS

+ +
.outer, .middle, .inner1, .inner2 {
+  display: block;
+  width:   520px;
+  padding: 15px;
+  margin:  15px;
+  text-decoration: none;
+}
+.outer {
+  border: 1px solid red;
+  color:  red;
+}
+.middle {
+  border: 1px solid green;
+  color:  green;
+  width:  460px;
+}
+.inner1, .inner2 {
+  border: 1px solid purple;
+  color:  purple;
+  width:  400px;
+}
+
+ +

JavaScript

+ +
const outer  = document.querySelector('.outer');
+const middle = document.querySelector('.middle');
+const inner1 = document.querySelector('.inner1');
+const inner2 = document.querySelector('.inner2');
+
+const capture = {
+  capture : true
+};
+const noneCapture = {
+  capture : false
+};
+const once = {
+  once : true
+};
+const noneOnce = {
+  once : false
+};
+const passive = {
+  passive : true
+};
+const nonePassive = {
+  passive : false
+};
+
+outer.addEventListener('click', onceHandler, once);
+outer.addEventListener('click', noneOnceHandler, noneOnce);
+middle.addEventListener('click', captureHandler, capture);
+middle.addEventListener('click', noneCaptureHandler, noneCapture);
+inner1.addEventListener('click', passiveHandler, passive);
+inner2.addEventListener('click', nonePassiveHandler, nonePassive);
+
+function onceHandler(event) {
+  alert('outer, once');
+}
+function noneOnceHandler(event) {
+  alert('outer, none-once, default');
+}
+function captureHandler(event) {
+  //event.stopImmediatePropagation();
+  alert('middle, capture');
+}
+function noneCaptureHandler(event) {
+  alert('middle, none-capture, default');
+}
+function passiveHandler(event) {
+  // Unable to preventDefault inside passive event listener invocation.
+  event.preventDefault();
+  alert('inner1, passive, open new page');
+}
+function nonePassiveHandler(event) {
+  event.preventDefault();
+  //event.stopPropagation();
+  alert('inner2, none-passive, default, not open new page');
+}
+
+ +

結果

+ +

外側、中央、内側のコンテナーをそれぞれクリックして、オプションがどのように動作するかを確認してください。

+ +

{{ EmbedLiveSample('Example_of_options_usage', 600, 310, '', 'Web/API/EventTarget/addEventListener') }}

+ +

options オブジェクトで特定の値を使用する前に、ユーザーのブラウザーがそれに対応していることを確認するのが良いでしょう。詳細は{{anch("Safely detecting option support", "オプションの対応の安全な検出")}}を参照してください。

+ +

その他の注

+ +

なぜ addEventListener() を使うのか

+ +

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

+ + + +

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

+ +

イベント配信中のリスナーの追加

+ +

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

+ +

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

+ +

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

+ +

ただし、無名関数をハンドラーとして使用する場合、そのようなリスナーは同じにはならないことに注意してください。無名関数はループ内であっても繰り返し呼び出されるだけで、同じソースコードを使って定義されていても同じにはならないためです。

+ +

ただし、このような場合に同じ名前の関数を繰り返し定義することは、より問題になる可能性があります (後述のメモリの問題を参照してください)。

+ +

ハンドラー内での "this" の値

+ +

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

+ +

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

+ +
my_element.addEventListener('click', function (e) {
+  console.log(this.className)           // logs the className of my_element
+  console.log(e.currentTarget === this) // logs `true`
+})
+
+ +

アロー関数は独自の this コンテキストを持たないことをお忘れなく。

+ +
my_element.addEventListener('click', (e) => {
+  console.log(this.className)           // WARNING: `this` is not `my_element`
+  console.log(e.currentTarget === this) // logs `false`
+})
+ +

イベントハンドラー (例えば {{domxref("GlobalEventHandlers.onclick", "onclick")}}) が HTML ソース内の要素に指定されていた場合、属性値の Javascirpt コードは、 addEventListener() を使用するような方法で this の値をバインドしたハンドラー関数に置き換えられます。コード内に this が現れた場合には、要素への参照を表します。

+ +
<table id="my_table" onclick="console.log(this.id);"><!-- `this` refers to the table; logs 'my_table' -->
+  ...
+</table>
+
+ +

this の値は、属性値の中のコードによって呼び出される関数内では、標準的な規則に従って振る舞うことに注意してください。これは次の例で示されています。

+ +
<script>
+  function logID() { console.log(this.id); }
+</script>
+<table id="my_table" onclick="logID();"><!-- when called, `this` will refer to the global object -->
+  ...
+</table>
+
+ +

thislogID() 内においては、グローバルオブジェクト {{domxref("Window")}} (または厳格モードの場合は undefinedになります。

+ +

bind() を使用した this の指定

+ +

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

+ +

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

+ +
const Something = function(element) {
+  // |this| is a newly created object
+  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); // これが仕掛けです
+}
+const s = new Something(document.body);
+
+ +

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

+ +
const Something = function(element) {
+  // |this| is a newly created object
+  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);
+}
+const s = new Something(document.body);
+
+ +

this の参照を扱うためのもう一つの方法は、 EventListener にアクセスする必要のあるフィールドを含むオブジェクトのメソッドを呼び出す関数を渡すことです。

+ +
class SomeClass {
+
+  constructor() {
+    this.name = 'Something Good';
+  }
+
+  register() {
+    const that = this;
+    window.addEventListener('keydown', function(e) { that.someMethod(e); });
+  }
+
+  someMethod(e) {
+    console.log(this.name);
+    switch(e.keyCode) {
+      case 5:
+        // some code here...
+        break;
+      case 6:
+        // some code here...
+        break;
+    }
+  }
+
+}
+
+const myObject = new SomeClass();
+myObject.register();
+ +

イベントリスナーのデータの出し入れ

+ +

イベントリスナーは島のようなもので、それらにデータを渡すのは非常に難しく、ましてや実行後にそれらからデータを取り出すのは非常に難しいと思われるかもしれません。イベントリスナーは、イベントオブジェクトという1つの引数を取るだけで、それは自動的にリスナーに渡され、返値が無視されるからです。では、どのようにしてデータを渡したり、取り出したりすることができるのでしょうか?これを行うための良い方法がいくつかあります。

+ +

"this" を使用したイベントリスナーへのデータの入力

+ +

前述の通り、 Function.prototype.bind() を使用すると this 参照変数を通じてイベントリスナーに値を渡すことができます。

+ +
const myButton = document.getElementById('my-button-id');
+const someString = 'Data';
+
+myButton.addEventListener('click', function () {
+  console.log(this);  // Expected Value: 'Data'
+}.bind(someString));
+
+ +

この方法は、イベントリスナーの中からプログラムでイベントリスナーがどの HTML 要素で発生したかを知る必要がない場合に適しています。これを行う主な利点は、実際に引数リストにデータを渡す場合とほぼ同じ方法でイベントリスナーがデータを受け取ることです。

+ +

外部スコープのプロパティを使用したイベントリスナーへのデータの入力

+ +

外部スコープに (const, let を付けた) 変数宣言が含まれている場合、そのスコープで宣言されたすべての内部関数はその変数にアクセスすることができます(外部関数/内部関数についてはこちらを、変数スコープについてはこちらを参照してください)。したがって、イベントリスナーの外部からデータにアクセスする最も簡単な方法の1つは、イベントリスナーが宣言されているスコープにアクセスできるようにすることです。

+ +
const myButton = document.getElementById('my-button-id');
+const someString = 'Data';
+
+myButton.addEventListener('click', function() {
+  console.log(someString);  // Expected Value: 'Data'
+
+  someString = 'Data Again';
+});
+
+console.log(someString);  // Expected Value: 'Data' (will never output 'Data Again')
+
+ +
+

注: 内側のスコープは外側のスコープにある const, let 変数にアクセスすることができますが、イベントリスナーの定義後に、同じ外側のスコープ内でこれらの変数にアクセスできるようになることは期待できません。なぜでしょうか?単純に、イベントリスナーが実行される頃には、イベントリスナーが定義されたスコープは既に実行を終了しているからです。

+
+ +

オブジェクトを用いたイベントリスナーのデータの出し入れ

+ +

JavaScript のほとんどの関数とは異なり、オブジェクトはそのオブジェクトを参照する変数がメモリ内に存在する限り、メモリ内に保持されます。それに加えて、オブジェクトはプロパティを持つことができ、参照によって渡すことができることから、スコープ間でデータを共有するための有力な候補となります。これについて調べてみましょう。

+ +
+

注: JavaScript の関数は厳密にはオブジェクトです。 (そのため、プロパティを持つことができ、メモリ内に永続的に存在する変数に代入されていれば、実行終了後もメモリ内に保持されます。)

+
+ +

オブジェクトを参照する変数がメモリに存在する限り、オブジェクトのプロパティを使用してメモリにデータを格納することができるので、実際にそれらを使用して、イベントリスナーにデータを渡し、イベントハンドラーが実行された後でデータに変更があった場合には、それを戻すことができます。この例を考えてみましょう。

+ +
const myButton = document.getElementById('my-button-id');
+const someObject = {aProperty: 'Data'};
+
+myButton.addEventListener('click', function() {
+  console.log(someObject.aProperty);  // Expected Value: 'Data'
+
+  someObject.aProperty = 'Data Again';  // Change the value
+});
+
+window.setInterval(function() {
+  if (someObject.aProperty === 'Data Again') {
+    console.log('Data Again: True');
+    someObject.aProperty = 'Data';  // Reset value to wait for next event execution
+  }
+}, 5000);
+
+ +

この例では、イベントリスナーとインターバル関数の両方が定義されているスコープは、 someObject.aProperty の元の値が変更される前に実行を終了していたとしても、イベントリスナーとインターバル関数の両方で someObject がメモリ内に (参照によって) 持続するため、両方とも同じデータにアクセスできます (つまり、一方がデータを変更したときに、もう一方がその変更に対応できます)。

+ +
+

注: オブジェクトは参照にで変数に格納されます。つまり、実際のデータのメモリの場所だけが変数に格納されます。とりわけ、これはオブジェクトを「格納」する変数が、実際に同じオブジェクト参照が代入 (「格納」) されている他の変数に影響を与えることができるということです。2つの変数が同じオブジェクトを参照している場合 (例えば、 let a = b = {aProperty: 'Yeah'};)、どちらかから変数のデータを変更すると、もう一方の変数に影響を与えます。

+
+ +
+

注: オブジェクトは参照によって変数に格納されているので、関数の実行を停止した後も、関数からオブジェクトを返す (データを失わないようにメモリに保存しておく) ことができます。

+
+ +

古い Internet Explorer と attachEvent

+ +

IE9 より前の Internet Explorer では、標準の addEventListener ではなく、 {{domxref("EventTarget.attachEvent", "attachEvent()")}} を使わなければなりません。 IE に対応するためには、上記の例を以下のように修正しなけれなりません。

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

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

+ +

attachEvent() メソッドは、ウェブページの特定の要素がサイズ変更されたことを検出するために onresize イベントを対応付けることができました。独自の mselementresize イベントは、イベントハンドラーを登録する addEventListener メソッドによって対応付けられた場合。 onresize と同様の機能を提供し、特定の HTML 要素の寸法が変更されたときに発行されます。

+ +

ポリフィル

+ +

次のコードをスクリプトの初めに書いておくと、 Internet Explorer 8 では対応していない addEventListener(), removeEventListener(), {{domxref("Event.preventDefault()")}}, {{domxref("Event.stopPropagation()")}} が動作するようになります。このコードは、 handleEvent()DOMContentLoaded イベントにも対応します。

+ +
+

注: useCapture に対応していないため、 IE 8 では代わりの方法はありません。以下のコードは IE 8 への対応を追加するだけです。また、 IE 8 用の代替モジュールは、標準モードのみで動作します。 doctype 宣言が必要です。

+
+ +
(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)、などのような関連するイベントハンドラも同様です。

+ +

これは本質的に {{glossary("DOM", "DOM 0")}} の一部であるため、イベントリスナーを追加するためのこのテクニックは非常に広く対応されており、特別なブラウザー間の互換コードを必要としません。これは、 (IE 8 以前のような) 非常に古いブラウザーに対応しなければならない場合に、イベントリスナーを動的に登録するために使用されます。 addEventListener のブラウザー対応の詳細については、下記の表を参照してください。

+ +

メモリに関する問題

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

上記の最初のケースでは、ループが繰り返されるたびに新しい (無名の) ハンドラー関数が作成されます。 2 番目のケースでは、以前に宣言された同じ関数がイベントハンドラーとして使用され、作成されるハンドラー関数が 1 つしかないため、メモリ消費量が少なくなります。さらに、最初のケースでは、無名関数への参照が保持されないため (ここでは、ループが作成する可能性のある複数の無名関数のいずれも保持されないため)、 {{domxref("EventTarget.removeEventListener", "removeEventListener()")}} を呼び出すことができません。2つ目のケースでは、 processEvent が関数への参照なので、 myElement.removeEventListener("click", processEvent, false) を実行することが可能です。

+ +

実際には、メモリ消費に関しては、関数への参照が保持されていないことが本当の問題ではなく、静的な関数への参照が保持されていないことが問題なのです。以下の問題ケースでは、どちらも関数への参照は保持されていますが、繰り返しのたびに再定義されているため、静的なものではありません。 3 つ目のケースでは、無名関数の参照が反復のたびに再割り当てされています。 4 番目のケースでは、関数の定義全体は不変ですが、 (コンパイラによって[[昇格]]されていない限り) 新しいものとして繰り返し定義されているので、静的ではありません。したがって、単純に[[複数の同一のイベントリスナー]]のように見えますが、どちらの場合も、各反復処理では、ハンドラー関数への独自の参照を持つ新しいリスナーが作成されます。しかし、関数の定義自体は変更されないので、重複するリスナーごとに同じ関数が呼び出される可能性があります (特にコードが最適化されている場合)。

+ +

また、どちらの場合も、関数への参照は保持されていたが、追加するごとに繰り返し再定義されていたので、上からの remove 文でリスナーを削除することができますが、最後に追加されたものだけが削除されるようになります。

+ +
// For illustration only: Note "MISTAKE" of [j] for [i] thus causing desired events to all attach to SAME element
+
+// ケース 3
+for(let i=0, j=0 ; i<els.length ; i++){
+  /* do lots of stuff with j */
+  els[j].addEventListener("click", processEvent = function(e){/*do something*/}, false);
+}
+
+// ケース 4
+for(let i=0, j=0 ; i<els.length ; i++){
+  /* do lots of stuff with j */
+  function processEvent(e){/*do something*/};
+  els[j].addEventListener("click", processEvent, false);
+}
+ +

パッシブリスナーを用いたスクロールの性能改善

+ +

仕様書によれば、 passive オプションの既定値は常に false です。しかし、これは特定のタッチイベントを扱うイベントリスナーが (特に) スクロールを処理しようとしている間にブラウザーのメインスレッドをブロックする可能性をもたらしており、スクロール処理中の性能が大幅に低下する結果になる可能性があります。

+ +

この問題を防ぐために、一部のブラウザー (特に Chrome と Firefox) では、文書レベルノードである {{domxref("Window")}}, {{domxref("Document")}}, {{domxref("Document.body")}} の {{event("touchstart")}} および {{event("touchmove")}} イベントの passive オプションの既定値を true に変更しています。これにより、イベントリスナーが呼び出されなくなるため、ユーザーがスクロールしている間にページのレンダリングをブロックすることができなくなります。

+ +
+

Note: この変更された動作を実装しているブラウザー (およびそれらのブラウザーのバージョン) を知りたい場合は、下記の互換性一覧表を参照してください。

+
+ +

この動作は下記のように、明示的に passive の値を false に設定することで上書きできます。

+ +
/* Feature detection */
+let passiveIfSupported = false;
+
+try {
+  window.addEventListener("test", null,
+    Object.defineProperty(
+      {},
+      "passive",
+      {
+        get: function() { passiveIfSupported = { passive: false }; }
+      }
+    )
+  );
+} catch(err) {}
+
+window.addEventListener('scroll', function(event) {
+  /* do something */
+  // can't use event.preventDefault();
+}, passiveIfSupported );
+
+ +

addEventListener()options 引数に対応していない古いブラウザーでは、これを使用しようとすると、機能検出を適切に使用せずに useCapture 引数の使用を防ぐことがあります。

+ +

基本的な {{event("scroll")}} イベントの passive の値を気にする必要はありません。キャンセルできないので、イベントリスナーはどのような場合でもページのレンダリングをブロックすることはできません。

+ +

仕様書

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
仕様書状態備考
{{SpecName("DOM WHATWG", "#dom-eventtarget-addeventlistener", "EventTarget.addEventListener()")}}{{Spec2("DOM WHATWG")}}
{{SpecName("DOM4", "#dom-eventtarget-addeventlistener", "EventTarget.addEventListener()")}}{{Spec2("DOM4")}}
{{SpecName("DOM2 Events", "#Events-EventTarget-addEventListener", "EventTarget.addEventListener()")}}{{Spec2("DOM2 Events")}}初回定義
+ +

ブラウザーの互換性

+ +

{{Compat("api.EventTarget.addEventListener", 3)}}

+ +

関連情報

+ + diff --git a/files/ja/web/api/eventtarget/dispatchevent/index.html b/files/ja/web/api/eventtarget/dispatchevent/index.html deleted file mode 100644 index a712cf21cd..0000000000 --- a/files/ja/web/api/eventtarget/dispatchevent/index.html +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: EventTarget.dispatchEvent() -slug: Web/API/EventTarget/dispatchEvent -tags: - - DOM - - Gecko - - Gecko DOM Reference - - 要更新 -translation_of: Web/API/EventTarget/dispatchEvent ---- -

{{APIRef("DOM Events")}}

- -

特定の {{domxref("EventTarget")}} に {{domxref("Event")}} をディスパッチし、影響する {{domxref("EventListener")}} を適切な順序で呼び出します。通常のイベント処理ルール(capturing フェーズと任意的な bubbling フェーズを含む)は dispatchEvent() で手動でディスパッチされたイベントにも適用されます。

- -

構文

- -
cancelled = !target.dispatchEvent(event)
-
- - - -

もしメソッド呼び出しの前にイベントが初期化されず、イベントのタイプが指定されなかった場合、あるいはイベントのタイプが null または空文字列だった場合、dispatchEventUNSPECIFIED_EVENT_TYPE_ERR を投げます。イベントハンドラから投げられた例外は、キャッチされなかった例外として報告されます。イベントハンドラは入れ子のコールスタック上で実行され、実行が完了するまで呼び出し元をブロックしますが、例外は呼び出し元まで伝播しません。

- -

- -

dispatchEvent は 作成-初期化-ディスパッチ プロセスの最後のステップであり、イベントを実装系のイベントモデルにディスパッチするのに使われます。イベントは document.createEvent メソッドを使って作成され、initEvent メソッド、またはその他の、initMouseEventinitUIEvent といったより具体的な初期化メソッドを使って初期化されます。

- -

Event オブジェクトのリファレンスも参照してください。

- -

- -

Creating and triggering events を参照。

- -

仕様書

- - diff --git a/files/ja/web/api/eventtarget/dispatchevent/index.md b/files/ja/web/api/eventtarget/dispatchevent/index.md new file mode 100644 index 0000000000..a712cf21cd --- /dev/null +++ b/files/ja/web/api/eventtarget/dispatchevent/index.md @@ -0,0 +1,42 @@ +--- +title: EventTarget.dispatchEvent() +slug: Web/API/EventTarget/dispatchEvent +tags: + - DOM + - Gecko + - Gecko DOM Reference + - 要更新 +translation_of: Web/API/EventTarget/dispatchEvent +--- +

{{APIRef("DOM Events")}}

+ +

特定の {{domxref("EventTarget")}} に {{domxref("Event")}} をディスパッチし、影響する {{domxref("EventListener")}} を適切な順序で呼び出します。通常のイベント処理ルール(capturing フェーズと任意的な bubbling フェーズを含む)は dispatchEvent() で手動でディスパッチされたイベントにも適用されます。

+ +

構文

+ +
cancelled = !target.dispatchEvent(event)
+
+ + + +

もしメソッド呼び出しの前にイベントが初期化されず、イベントのタイプが指定されなかった場合、あるいはイベントのタイプが null または空文字列だった場合、dispatchEventUNSPECIFIED_EVENT_TYPE_ERR を投げます。イベントハンドラから投げられた例外は、キャッチされなかった例外として報告されます。イベントハンドラは入れ子のコールスタック上で実行され、実行が完了するまで呼び出し元をブロックしますが、例外は呼び出し元まで伝播しません。

+ +

+ +

dispatchEvent は 作成-初期化-ディスパッチ プロセスの最後のステップであり、イベントを実装系のイベントモデルにディスパッチするのに使われます。イベントは document.createEvent メソッドを使って作成され、initEvent メソッド、またはその他の、initMouseEventinitUIEvent といったより具体的な初期化メソッドを使って初期化されます。

+ +

Event オブジェクトのリファレンスも参照してください。

+ +

+ +

Creating and triggering events を参照。

+ +

仕様書

+ + diff --git a/files/ja/web/api/eventtarget/eventtarget/index.html b/files/ja/web/api/eventtarget/eventtarget/index.html deleted file mode 100644 index 7eb3984f2e..0000000000 --- a/files/ja/web/api/eventtarget/eventtarget/index.html +++ /dev/null @@ -1,74 +0,0 @@ ---- -title: EventTarget() -slug: Web/API/EventTarget/EventTarget -translation_of: Web/API/EventTarget/EventTarget ---- -
{{APIRef("DOM Events")}}
- -

EventTarget() コンストラクタは新しい {{domxref("EventTarget")}} オブジェクトインスタンスをつくります。

- -

構文

- -
var myEventTarget = new EventTarget();
- -

引数

- -

なし。

- -

戻り値

- -

{{domxref("EventTarget")}} オブジェクトのインスタンス。

- -

- -
class MyEventTarget extends EventTarget {
-  constructor(mySecret) {
-    super();
-    this._secret = mySecret;
-  }
-
-  get secret() { return this._secret; }
-};
-
-let myEventTarget = new MyEventTarget(5);
-let value = myEventTarget.secret;  // == 5
-myEventTarget.addEventListener("foo", function(e) {
-  this._secret = e.detail;
-});
-
-let event = new CustomEvent("foo", { detail: 7 });
-myEventTarget.dispatchEvent(event);
-let newValue = myEventTarget.secret; // == 7
- -

仕様

- - - - - - - - - - - - - - -
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#dom-eventtarget-eventtarget', 'EventTarget() constructor')}}{{Spec2('DOM WHATWG')}} 
- -

ブラウザの実装状況

- -
- - -

{{Compat("api.EventTarget.EventTarget")}}

-
- -

関連情報

- - - -

 

diff --git a/files/ja/web/api/eventtarget/eventtarget/index.md b/files/ja/web/api/eventtarget/eventtarget/index.md new file mode 100644 index 0000000000..7eb3984f2e --- /dev/null +++ b/files/ja/web/api/eventtarget/eventtarget/index.md @@ -0,0 +1,74 @@ +--- +title: EventTarget() +slug: Web/API/EventTarget/EventTarget +translation_of: Web/API/EventTarget/EventTarget +--- +
{{APIRef("DOM Events")}}
+ +

EventTarget() コンストラクタは新しい {{domxref("EventTarget")}} オブジェクトインスタンスをつくります。

+ +

構文

+ +
var myEventTarget = new EventTarget();
+ +

引数

+ +

なし。

+ +

戻り値

+ +

{{domxref("EventTarget")}} オブジェクトのインスタンス。

+ +

+ +
class MyEventTarget extends EventTarget {
+  constructor(mySecret) {
+    super();
+    this._secret = mySecret;
+  }
+
+  get secret() { return this._secret; }
+};
+
+let myEventTarget = new MyEventTarget(5);
+let value = myEventTarget.secret;  // == 5
+myEventTarget.addEventListener("foo", function(e) {
+  this._secret = e.detail;
+});
+
+let event = new CustomEvent("foo", { detail: 7 });
+myEventTarget.dispatchEvent(event);
+let newValue = myEventTarget.secret; // == 7
+ +

仕様

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('DOM WHATWG', '#dom-eventtarget-eventtarget', 'EventTarget() constructor')}}{{Spec2('DOM WHATWG')}} 
+ +

ブラウザの実装状況

+ +
+ + +

{{Compat("api.EventTarget.EventTarget")}}

+
+ +

関連情報

+ + + +

 

diff --git a/files/ja/web/api/eventtarget/index.html b/files/ja/web/api/eventtarget/index.html deleted file mode 100644 index 6ace39e14c..0000000000 --- a/files/ja/web/api/eventtarget/index.html +++ /dev/null @@ -1,122 +0,0 @@ ---- -title: EventTarget -slug: Web/API/EventTarget -tags: - - API - - DOM - - DOM Events - - EventTarget - - Interface -translation_of: Web/API/EventTarget ---- -

{{ApiRef("DOM Events")}}

- -

EventTarget は DOM インターフェイスで、イベントを受け取ることや、リスナーを持つことができるオブジェクトが実装しています。

- -

{{domxref("Element")}}、{{domxref("Document")}}、{{domxref("Window")}} は、最も一般的なイベントターゲットですが、他のオブジェクトも、例えば {{domxref("XMLHttpRequest")}}、{{domxref("AudioNode")}}、{{domxref("AudioContext")}} などもイベントターゲットになります。

- -

多くのイベントターゲット (要素、文書、ウィンドウを含む) は、イベントハンドラーを設定するのに onイベント名 プロパティや属性を使用することもできます。

- -

{{InheritanceDiagram}}

- -

コンストラクター

- -
-
{{domxref("EventTarget.EventTarget()","EventTarget()")}}
-
新しい EventTarget オブジェクトのインスタンスを作成します。
-
- -

メソッド

- -
-
{{domxref("EventTarget.addEventListener()", "EventTarget.addEventListener()")}}
-
特定のイベント種別のイベントハンドラーを EventTarget に登録します。
-
{{domxref("EventTarget.removeEventListener()", "EventTarget.removeEventListener()")}}
-
EventTarget からイベントリスナーを削除します。
-
{{domxref("EventTarget.dispatchEvent()", "EventTarget.dispatchEvent()")}}
-
この EventTarget にイベントを送出します。
-
- - -

- -

EventTarget の簡単な実装

- -
var EventTarget = function() {
-  this.listeners = {};
-};
-
-EventTarget.prototype.listeners = null;
-EventTarget.prototype.addEventListener = function(type, callback) {
-  if (!(type in this.listeners)) {
-    this.listeners[type] = [];
-  }
-  this.listeners[type].push(callback);
-};
-
-EventTarget.prototype.removeEventListener = function(type, callback) {
-  if (!(type in this.listeners)) {
-    return;
-  }
-  var stack = this.listeners[type];
-  for (var i = 0, l = stack.length; i < l; i++) {
-    if (stack[i] === callback){
-      stack.splice(i, 1);
-      return;
-    }
-  }
-};
-
-EventTarget.prototype.dispatchEvent = function(event) {
-  if (!(event.type in this.listeners)) {
-    return true;
-  }
-  var stack = this.listeners[event.type].slice();
-
-  for (var i = 0, l = stack.length; i < l; i++) {
-    stack[i].call(this, event);
-  }
-  return !event.defaultPrevented;
-};
-
- -

仕様書

- - - - - - - - - - - - - - - - - - - - - - - - - - -
仕様書状態況備考
{{SpecName('DOM WHATWG', '#interface-eventtarget', 'EventTarget')}}{{Spec2('DOM WHATWG')}}変更なし。
{{SpecName('DOM3 Events', 'DOM3-Events.html#interface-EventTarget', 'EventTarget')}}{{Spec2('DOM3 Events')}}いくつかの引数が任意になったり (listener)、 null 値を許可するようになったりした (useCapture)。
{{SpecName('DOM2 Events', 'events.html#Events-EventTarget', 'EventTarget')}}{{Spec2('DOM2 Events')}}初回定義。
- -

ブラウザーの互換性

- -

{{Compat("api.EventTarget")}}

- -

関連情報

- - diff --git a/files/ja/web/api/eventtarget/index.md b/files/ja/web/api/eventtarget/index.md new file mode 100644 index 0000000000..6ace39e14c --- /dev/null +++ b/files/ja/web/api/eventtarget/index.md @@ -0,0 +1,122 @@ +--- +title: EventTarget +slug: Web/API/EventTarget +tags: + - API + - DOM + - DOM Events + - EventTarget + - Interface +translation_of: Web/API/EventTarget +--- +

{{ApiRef("DOM Events")}}

+ +

EventTarget は DOM インターフェイスで、イベントを受け取ることや、リスナーを持つことができるオブジェクトが実装しています。

+ +

{{domxref("Element")}}、{{domxref("Document")}}、{{domxref("Window")}} は、最も一般的なイベントターゲットですが、他のオブジェクトも、例えば {{domxref("XMLHttpRequest")}}、{{domxref("AudioNode")}}、{{domxref("AudioContext")}} などもイベントターゲットになります。

+ +

多くのイベントターゲット (要素、文書、ウィンドウを含む) は、イベントハンドラーを設定するのに onイベント名 プロパティや属性を使用することもできます。

+ +

{{InheritanceDiagram}}

+ +

コンストラクター

+ +
+
{{domxref("EventTarget.EventTarget()","EventTarget()")}}
+
新しい EventTarget オブジェクトのインスタンスを作成します。
+
+ +

メソッド

+ +
+
{{domxref("EventTarget.addEventListener()", "EventTarget.addEventListener()")}}
+
特定のイベント種別のイベントハンドラーを EventTarget に登録します。
+
{{domxref("EventTarget.removeEventListener()", "EventTarget.removeEventListener()")}}
+
EventTarget からイベントリスナーを削除します。
+
{{domxref("EventTarget.dispatchEvent()", "EventTarget.dispatchEvent()")}}
+
この EventTarget にイベントを送出します。
+
+ + +

+ +

EventTarget の簡単な実装

+ +
var EventTarget = function() {
+  this.listeners = {};
+};
+
+EventTarget.prototype.listeners = null;
+EventTarget.prototype.addEventListener = function(type, callback) {
+  if (!(type in this.listeners)) {
+    this.listeners[type] = [];
+  }
+  this.listeners[type].push(callback);
+};
+
+EventTarget.prototype.removeEventListener = function(type, callback) {
+  if (!(type in this.listeners)) {
+    return;
+  }
+  var stack = this.listeners[type];
+  for (var i = 0, l = stack.length; i < l; i++) {
+    if (stack[i] === callback){
+      stack.splice(i, 1);
+      return;
+    }
+  }
+};
+
+EventTarget.prototype.dispatchEvent = function(event) {
+  if (!(event.type in this.listeners)) {
+    return true;
+  }
+  var stack = this.listeners[event.type].slice();
+
+  for (var i = 0, l = stack.length; i < l; i++) {
+    stack[i].call(this, event);
+  }
+  return !event.defaultPrevented;
+};
+
+ +

仕様書

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
仕様書状態況備考
{{SpecName('DOM WHATWG', '#interface-eventtarget', 'EventTarget')}}{{Spec2('DOM WHATWG')}}変更なし。
{{SpecName('DOM3 Events', 'DOM3-Events.html#interface-EventTarget', 'EventTarget')}}{{Spec2('DOM3 Events')}}いくつかの引数が任意になったり (listener)、 null 値を許可するようになったりした (useCapture)。
{{SpecName('DOM2 Events', 'events.html#Events-EventTarget', 'EventTarget')}}{{Spec2('DOM2 Events')}}初回定義。
+ +

ブラウザーの互換性

+ +

{{Compat("api.EventTarget")}}

+ +

関連情報

+ + diff --git a/files/ja/web/api/eventtarget/removeeventlistener/index.html b/files/ja/web/api/eventtarget/removeeventlistener/index.html deleted file mode 100644 index c15c61d051..0000000000 --- a/files/ja/web/api/eventtarget/removeeventlistener/index.html +++ /dev/null @@ -1,220 +0,0 @@ ---- -title: EventTarget.removeEventListener -slug: Web/API/EventTarget/removeEventListener -tags: - - API - - DOM - - DOM Element Methods - - EventTarget - - Gecko - - Method - - Reference - - browser compatibility - - removeEventListener - - メソッド -translation_of: Web/API/EventTarget/removeEventListener ---- -
{{APIRef("DOM Events")}}
- -

EventTarget.removeEventListener() メソッドは、 {{domxref("EventTarget")}} から、以前に {{domxref("EventTarget.addEventListener()")}} で登録されたイベントリスナーを削除します。削除されるイベントリスナーはイベントの型、イベントリスナー関数そのもの、マッチングプロセスに影響を与えるさまざまな任意のオプションを使用して識別します。{{anch("Matching event listeners for removal", "削除するイベントリスナーのマッチング")}} をご覧ください。

- -

構文

- -
target.removeEventListener(type, listener[, options]);
-target.removeEventListener(type, listener[, useCapture]);
- -

引数

- -
-
type
-
イベントリスナーを削除するイベントの型を表す文字列。
-
listener
-
イベントターゲットから削除するイベントハンドラーの {{domxref("EventListener")}} 関数です。
-
options {{optional_inline}}
-
イベントリスナーに関する特性を指定する、オプションのオブジェクトです。次のオプションが使用できます。 -
    -
  • capture: この型のイベントが、DOM ツリーで下位にある任意の EventTarget へ発送される前に listener へ発送されることを示す {{jsxref("Boolean")}} です。
  • -
  • {{non-standard_inline}} mozSystemGroup: XBL または Firefox の chrome で実行するコードに限り有効であり、リスナーがシステムグループに追加されているかを定義する {{jsxref("Boolean")}} です。
  • -
-
-
useCapture {{optional_inline}}
-
削除する {{domxref("EventListener")}} がキャプチャーリスナーとして登録されているかを指定します。この引数を省略した場合は、既定値の false であるとみなします。
-
リスナーが 2 回登録されていてひとつはキャプチャー、もうひとつは非キャプチャーである場合は、それぞれを個別に削除します。キャプチャーリスナーを削除しても、同じリスナーの非キャプチャーリスナーには影響がありません。逆も同様です。
-
- -

返値

- -

undefined です。

- -

削除するイベントリスナーのマッチング

- -

{{domxref("EventTarget.addEventListener", "addEventListener()")}} を呼び出して以前に追加したイベントリスナーは、最終的に削除が必要な状態になることがあります。removeEventListener() に同じ type および listener の引数を指定しなければならないことは明らかですが、optionsuseCapture の引数はどうでしょうか?

- -

addEventListener() は、オプションが異なっていれば同じ型に対して同じリスナーを複数追加できますが、 removeEventListener() が確認するオプションは capture/useCapture フラグだけです。一致させるためにこの値は removeEventListener() で一致していなければなりませんが、他の値は一致していなくてもかまいません。

- -

例えば、以下の addEventListener() で考えましょう。

- -
element.addEventListener("mousedown", handleMouseDown, true);
- -

そして、以下 2 つの removeEventListener() の呼び出しについて考えましょう。

- -
element.removeEventListener("mousedown", handleMouseDown, false);     // 失敗
-element.removeEventListener("mousedown", handleMouseDown, true);      // 成功
-
- -

1 番目の呼び出しは、useCapture の値が異なるため失敗します。2 番目は、useCapture が一致しますので成功します。

- -

次に、以下の呼び出しを考えましょう。

- -
element.addEventListener("mousedown", handleMouseDown, { passive: true });
- -

ここでは passivetrue に設定した options を指定していますが、他のオプションは既定値の false のままです。

- -

では、以下の removeEventListener() の呼び出しについて、順番に見ていきましょう。capture または useCapturetrue であるものは失敗して、そのほかは成功します。capture の設定だけが removeEventListener() に関与します。

- -
element.removeEventListener("mousedown", handleMouseDown, { passive: true });     // 成功
-element.removeEventListener("mousedown", handleMouseDown, { capture: false });    // 成功
-element.removeEventListener("mousedown", handleMouseDown, { capture: true });     // 失敗
-element.removeEventListener("mousedown", handleMouseDown, { passive: false });    // 成功
-element.removeEventListener("mousedown", handleMouseDown, false);                 // 成功
-element.removeEventListener("mousedown", handleMouseDown, true);                  // 失敗
-
- -

一部のブラウザーはこれとは動作が異なることは注目する価値があり、他に特別な理由がない限り removeEventListener() を呼び出すときは、addEventListener() を呼び出したときと同じ値を使用するとよいでしょう。

- -

メモ

- -

{{domxref("EventListener")}} がイベントを処理中である {{domxref("EventTarget")}} から削除された場合、現在のアクションによってそのイベントリスナーが実行されることはありません。{{domxref("EventListener")}} は、決して削除された後に実行されることはありません。ただし、再追加することができます。

- -

EventTarget 上にある現在のどの {{domxref("EventListener")}} も指定していない引数付きの removeEventListener() は、何の効果もありません。

- -

- -

この例は、click ベースのイベントリスナーを追加して mouseover ベースのイベントリスナーを削除する方法を示します。

- -
var body = document.querySelector('body'),
-    clickTarget = document.getElementById('click-target'),
-    mouseOverTarget = document.getElementById('mouse-over-target'),
-    toggle = false;
-
-function makeBackgroundYellow() {
-    'use strict';
-
-    if (toggle) {
-        body.style.backgroundColor = 'white';
-    } else {
-        body.style.backgroundColor = 'yellow';
-    }
-
-    toggle = !toggle;
-}
-
-clickTarget.addEventListener('click',
-    makeBackgroundYellow,
-    false
-);
-
-mouseOverTarget.addEventListener('mouseover', function () {
-    'use strict';
-
-    clickTarget.removeEventListener('click',
-        makeBackgroundYellow,
-        false
-    );
-});
-
- -

仕様書

- - - - - - - - - - - - - - - - - - - - - - - - - - -
仕様書状態備考
{{SpecName("DOM WHATWG", "#dom-eventtarget-removeeventlistener", "EventTarget.removeEventListener()")}}{{Spec2("DOM WHATWG")}} 
{{SpecName("DOM4", "#dom-eventtarget-removeeventlistener", "EventTarget.removeEventListener()")}}{{Spec2("DOM4")}} 
{{SpecName("DOM2 Events", "#Events-EventTarget-removeEventListener", "EventTarget.removeEventListener()")}}{{Spec2("DOM2 Events")}}初回定義
- -

ブラウザーの対応

- -
{{Compat("api.EventTarget.removeEventListener", 3)}}
- -

古いブラウザーをサポートするためのポリフィル

- -

addEventListener() および removeEventListener() は、古いブラウザーでは提供されていません。以下のコードをスクリプトの先頭に挿入するとこの問題を回避でき、 addEventListener() および removeEventListener() にネイティブに対応していない実装でもこれらを使用できます。ただし、 Element.prototype が Internet Explorer 8 までサポートされていなかったため、この方法は Internet Explorer 7 およびそれ以前では動作しません。

- -
if (!Element.prototype.addEventListener) {
-  var oListeners = {};
-  function runListeners(oEvent) {
-    if (!oEvent) { oEvent = window.event; }
-    for (var iLstId = 0, iElId = 0, oEvtListeners = oListeners[oEvent.type]; iElId < oEvtListeners.aEls.length; iElId++) {
-      if (oEvtListeners.aEls[iElId] === this) {
-        for (iLstId; iLstId < oEvtListeners.aEvts[iElId].length; iLstId++) { oEvtListeners.aEvts[iElId][iLstId].call(this, oEvent); }
-        break;
-      }
-    }
-  }
-  Element.prototype.addEventListener = function (sEventType, fListener /*, useCapture (will be ignored!) */) {
-    if (oListeners.hasOwnProperty(sEventType)) {
-      var oEvtListeners = oListeners[sEventType];
-      for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) {
-        if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; }
-      }
-      if (nElIdx === -1) {
-        oEvtListeners.aEls.push(this);
-        oEvtListeners.aEvts.push([fListener]);
-        this["on" + sEventType] = runListeners;
-      } else {
-        var aElListeners = oEvtListeners.aEvts[nElIdx];
-        if (this["on" + sEventType] !== runListeners) {
-          aElListeners.splice(0);
-          this["on" + sEventType] = runListeners;
-        }
-        for (var iLstId = 0; iLstId < aElListeners.length; iLstId++) {
-          if (aElListeners[iLstId] === fListener) { return; }
-        }
-        aElListeners.push(fListener);
-      }
-    } else {
-      oListeners[sEventType] = { aEls: [this], aEvts: [ [fListener] ] };
-      this["on" + sEventType] = runListeners;
-    }
-  };
-  Element.prototype.removeEventListener = function (sEventType, fListener /*, useCapture (will be ignored!) */) {
-    if (!oListeners.hasOwnProperty(sEventType)) { return; }
-    var oEvtListeners = oListeners[sEventType];
-    for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) {
-      if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; }
-    }
-    if (nElIdx === -1) { return; }
-    for (var iLstId = 0, aElListeners = oEvtListeners.aEvts[nElIdx]; iLstId < aElListeners.length; iLstId++) {
-      if (aElListeners[iLstId] === fListener) { aElListeners.splice(iLstId, 1); }
-    }
-  };
-}
-
- -

関連情報

- - diff --git a/files/ja/web/api/eventtarget/removeeventlistener/index.md b/files/ja/web/api/eventtarget/removeeventlistener/index.md new file mode 100644 index 0000000000..c15c61d051 --- /dev/null +++ b/files/ja/web/api/eventtarget/removeeventlistener/index.md @@ -0,0 +1,220 @@ +--- +title: EventTarget.removeEventListener +slug: Web/API/EventTarget/removeEventListener +tags: + - API + - DOM + - DOM Element Methods + - EventTarget + - Gecko + - Method + - Reference + - browser compatibility + - removeEventListener + - メソッド +translation_of: Web/API/EventTarget/removeEventListener +--- +
{{APIRef("DOM Events")}}
+ +

EventTarget.removeEventListener() メソッドは、 {{domxref("EventTarget")}} から、以前に {{domxref("EventTarget.addEventListener()")}} で登録されたイベントリスナーを削除します。削除されるイベントリスナーはイベントの型、イベントリスナー関数そのもの、マッチングプロセスに影響を与えるさまざまな任意のオプションを使用して識別します。{{anch("Matching event listeners for removal", "削除するイベントリスナーのマッチング")}} をご覧ください。

+ +

構文

+ +
target.removeEventListener(type, listener[, options]);
+target.removeEventListener(type, listener[, useCapture]);
+ +

引数

+ +
+
type
+
イベントリスナーを削除するイベントの型を表す文字列。
+
listener
+
イベントターゲットから削除するイベントハンドラーの {{domxref("EventListener")}} 関数です。
+
options {{optional_inline}}
+
イベントリスナーに関する特性を指定する、オプションのオブジェクトです。次のオプションが使用できます。 +
    +
  • capture: この型のイベントが、DOM ツリーで下位にある任意の EventTarget へ発送される前に listener へ発送されることを示す {{jsxref("Boolean")}} です。
  • +
  • {{non-standard_inline}} mozSystemGroup: XBL または Firefox の chrome で実行するコードに限り有効であり、リスナーがシステムグループに追加されているかを定義する {{jsxref("Boolean")}} です。
  • +
+
+
useCapture {{optional_inline}}
+
削除する {{domxref("EventListener")}} がキャプチャーリスナーとして登録されているかを指定します。この引数を省略した場合は、既定値の false であるとみなします。
+
リスナーが 2 回登録されていてひとつはキャプチャー、もうひとつは非キャプチャーである場合は、それぞれを個別に削除します。キャプチャーリスナーを削除しても、同じリスナーの非キャプチャーリスナーには影響がありません。逆も同様です。
+
+ +

返値

+ +

undefined です。

+ +

削除するイベントリスナーのマッチング

+ +

{{domxref("EventTarget.addEventListener", "addEventListener()")}} を呼び出して以前に追加したイベントリスナーは、最終的に削除が必要な状態になることがあります。removeEventListener() に同じ type および listener の引数を指定しなければならないことは明らかですが、optionsuseCapture の引数はどうでしょうか?

+ +

addEventListener() は、オプションが異なっていれば同じ型に対して同じリスナーを複数追加できますが、 removeEventListener() が確認するオプションは capture/useCapture フラグだけです。一致させるためにこの値は removeEventListener() で一致していなければなりませんが、他の値は一致していなくてもかまいません。

+ +

例えば、以下の addEventListener() で考えましょう。

+ +
element.addEventListener("mousedown", handleMouseDown, true);
+ +

そして、以下 2 つの removeEventListener() の呼び出しについて考えましょう。

+ +
element.removeEventListener("mousedown", handleMouseDown, false);     // 失敗
+element.removeEventListener("mousedown", handleMouseDown, true);      // 成功
+
+ +

1 番目の呼び出しは、useCapture の値が異なるため失敗します。2 番目は、useCapture が一致しますので成功します。

+ +

次に、以下の呼び出しを考えましょう。

+ +
element.addEventListener("mousedown", handleMouseDown, { passive: true });
+ +

ここでは passivetrue に設定した options を指定していますが、他のオプションは既定値の false のままです。

+ +

では、以下の removeEventListener() の呼び出しについて、順番に見ていきましょう。capture または useCapturetrue であるものは失敗して、そのほかは成功します。capture の設定だけが removeEventListener() に関与します。

+ +
element.removeEventListener("mousedown", handleMouseDown, { passive: true });     // 成功
+element.removeEventListener("mousedown", handleMouseDown, { capture: false });    // 成功
+element.removeEventListener("mousedown", handleMouseDown, { capture: true });     // 失敗
+element.removeEventListener("mousedown", handleMouseDown, { passive: false });    // 成功
+element.removeEventListener("mousedown", handleMouseDown, false);                 // 成功
+element.removeEventListener("mousedown", handleMouseDown, true);                  // 失敗
+
+ +

一部のブラウザーはこれとは動作が異なることは注目する価値があり、他に特別な理由がない限り removeEventListener() を呼び出すときは、addEventListener() を呼び出したときと同じ値を使用するとよいでしょう。

+ +

メモ

+ +

{{domxref("EventListener")}} がイベントを処理中である {{domxref("EventTarget")}} から削除された場合、現在のアクションによってそのイベントリスナーが実行されることはありません。{{domxref("EventListener")}} は、決して削除された後に実行されることはありません。ただし、再追加することができます。

+ +

EventTarget 上にある現在のどの {{domxref("EventListener")}} も指定していない引数付きの removeEventListener() は、何の効果もありません。

+ +

+ +

この例は、click ベースのイベントリスナーを追加して mouseover ベースのイベントリスナーを削除する方法を示します。

+ +
var body = document.querySelector('body'),
+    clickTarget = document.getElementById('click-target'),
+    mouseOverTarget = document.getElementById('mouse-over-target'),
+    toggle = false;
+
+function makeBackgroundYellow() {
+    'use strict';
+
+    if (toggle) {
+        body.style.backgroundColor = 'white';
+    } else {
+        body.style.backgroundColor = 'yellow';
+    }
+
+    toggle = !toggle;
+}
+
+clickTarget.addEventListener('click',
+    makeBackgroundYellow,
+    false
+);
+
+mouseOverTarget.addEventListener('mouseover', function () {
+    'use strict';
+
+    clickTarget.removeEventListener('click',
+        makeBackgroundYellow,
+        false
+    );
+});
+
+ +

仕様書

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
仕様書状態備考
{{SpecName("DOM WHATWG", "#dom-eventtarget-removeeventlistener", "EventTarget.removeEventListener()")}}{{Spec2("DOM WHATWG")}} 
{{SpecName("DOM4", "#dom-eventtarget-removeeventlistener", "EventTarget.removeEventListener()")}}{{Spec2("DOM4")}} 
{{SpecName("DOM2 Events", "#Events-EventTarget-removeEventListener", "EventTarget.removeEventListener()")}}{{Spec2("DOM2 Events")}}初回定義
+ +

ブラウザーの対応

+ +
{{Compat("api.EventTarget.removeEventListener", 3)}}
+ +

古いブラウザーをサポートするためのポリフィル

+ +

addEventListener() および removeEventListener() は、古いブラウザーでは提供されていません。以下のコードをスクリプトの先頭に挿入するとこの問題を回避でき、 addEventListener() および removeEventListener() にネイティブに対応していない実装でもこれらを使用できます。ただし、 Element.prototype が Internet Explorer 8 までサポートされていなかったため、この方法は Internet Explorer 7 およびそれ以前では動作しません。

+ +
if (!Element.prototype.addEventListener) {
+  var oListeners = {};
+  function runListeners(oEvent) {
+    if (!oEvent) { oEvent = window.event; }
+    for (var iLstId = 0, iElId = 0, oEvtListeners = oListeners[oEvent.type]; iElId < oEvtListeners.aEls.length; iElId++) {
+      if (oEvtListeners.aEls[iElId] === this) {
+        for (iLstId; iLstId < oEvtListeners.aEvts[iElId].length; iLstId++) { oEvtListeners.aEvts[iElId][iLstId].call(this, oEvent); }
+        break;
+      }
+    }
+  }
+  Element.prototype.addEventListener = function (sEventType, fListener /*, useCapture (will be ignored!) */) {
+    if (oListeners.hasOwnProperty(sEventType)) {
+      var oEvtListeners = oListeners[sEventType];
+      for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) {
+        if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; }
+      }
+      if (nElIdx === -1) {
+        oEvtListeners.aEls.push(this);
+        oEvtListeners.aEvts.push([fListener]);
+        this["on" + sEventType] = runListeners;
+      } else {
+        var aElListeners = oEvtListeners.aEvts[nElIdx];
+        if (this["on" + sEventType] !== runListeners) {
+          aElListeners.splice(0);
+          this["on" + sEventType] = runListeners;
+        }
+        for (var iLstId = 0; iLstId < aElListeners.length; iLstId++) {
+          if (aElListeners[iLstId] === fListener) { return; }
+        }
+        aElListeners.push(fListener);
+      }
+    } else {
+      oListeners[sEventType] = { aEls: [this], aEvts: [ [fListener] ] };
+      this["on" + sEventType] = runListeners;
+    }
+  };
+  Element.prototype.removeEventListener = function (sEventType, fListener /*, useCapture (will be ignored!) */) {
+    if (!oListeners.hasOwnProperty(sEventType)) { return; }
+    var oEvtListeners = oListeners[sEventType];
+    for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) {
+      if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; }
+    }
+    if (nElIdx === -1) { return; }
+    for (var iLstId = 0, aElListeners = oEvtListeners.aEvts[nElIdx]; iLstId < aElListeners.length; iLstId++) {
+      if (aElListeners[iLstId] === fListener) { aElListeners.splice(iLstId, 1); }
+    }
+  };
+}
+
+ +

関連情報

+ + -- cgit v1.2.3-54-g00ecf