JavaScript/EventTarget

EventTargetオブジェクト

はじめに

ウェブブラウザでのJavaScriptプログラミングにおいて、イベント処理は中心的な役割を果たします。ユーザーがボタンをクリックしたり、キーボードで入力したり、ページがロードされたりするたびに、イベントが発生します。これらのイベントを検知し、適切に対応することで、インタラクティブなウェブアプリケーションを構築できます。EventTargetオブジェクトは、このイベント処理の根幹をなす重要な仕組みです。

EventTargetとは

EventTargetは、イベントを受け取り、それらを処理するためのメソッドを提供するインターフェースです。DOM(Document Object Model)内のほとんどのオブジェクトは、このEventTargetインターフェースを実装しています。具体的には、ElementHTMLDivElement(div), HTMLButtonElement(button), HTMLParagraphElement(p)など)、DocumentWindowXMLHttpRequestといったオブジェクトがEventTargetを継承しています。

EventTargetインターフェースの最も重要な役割は、イベントリスナーの追加、削除、イベントのディスパッチを可能にすることです。

主要なメソッド

EventTargetオブジェクトには、以下の主要なメソッドが存在します。

メソッド名 構文 説明
addEventListener target.addEventListener(type, listener[, options]) 指定した要素にイベントリスナーを追加します
removeEventListener target.removeEventListener(type, listener[, options]) 指定した要素からイベントリスナーを削除します
dispatchEvent target.dispatchEvent(event) 特定のイベントを手動で発生させます

それぞれのメソッドについて詳しく見ていきましょう。

addEventListener メソッド

addEventListenerメソッドは、指定された要素にイベントリスナーを追加します。このメソッドにより、特定のイベントが発生した時に実行する関数(リスナー)を登録できます。

element.addEventListener(type, listener[, options]);

パラメータの詳細:

  • type: リスナーを登録するイベントの種類を表す文字列(例:"click", "mouseover", "keydown"など)
  • listener: イベントが発火したときに呼び出される関数
  • options: リスナーの特性を指定するオプションのオブジェクト
    • capture: イベントキャプチャフェーズで処理するかどうか(デフォルトはfalse)
    • once: リスナーを一度だけ呼び出すかどうか(デフォルトはfalse)
    • passive: リスナーがpreventDefault()を呼び出さないことを示す(デフォルトはfalse)

具体的な使用例を見てみましょう。以下は、ボタンがクリックされた時に挨拶メッセージを表示する例です。

// HTMLに存在するボタン要素を取得
const button = document.getElementById('greetButton');

// クリックイベントのリスナーを追加
button.addEventListener('click', function() {
  alert('こんにちは!');
});

上記のコードでは、IDが"greetButton"のHTML要素にクリックイベントのリスナーを追加しています。ユーザーがボタンをクリックすると、アラートでメッセージが表示されます。

removeEventListener メソッド

removeEventListenerメソッドは、以前に追加したイベントリスナーを削除します。イベントリスナーを削除するには、追加した時と同じ引数を指定する必要があります。

element.removeEventListener(type, listener[, options]);

パラメータはaddEventListenerと同じですが、削除対象のリスナーを正確に特定するために使用します。

リスナーを削除するためには、関数を変数に保存しておく必要があることに注意してください。

// リスナー関数を変数に保存
const greetUser = function() {
  alert('こんにちは!');
};

// ボタンにイベントリスナーを追加
button.addEventListener('click', greetUser);

// 後でイベントリスナーを削除
button.removeEventListener('click', greetUser);

このように、リスナー関数を変数に保存しておくことで、後から正確に削除できます。無名関数を直接使用した場合は削除できないため、注意が必要です。

dispatchEvent メソッド

dispatchEventメソッドは、イベントを手動で発火させるために使用します。これにより、ユーザーの操作がなくてもプログラム的にイベントを発生させることができます。

element.dispatchEvent(event);

パラメータ:

  • event: ディスパッチするEventオブジェクトのインスタンス

使用例として、ボタンのクリックイベントを手動で発火させる方法を見てみましょう。

// ボタン要素を取得
const button = document.getElementById('greetButton');

// クリックイベントリスナーを設定
button.addEventListener('click', function() {
  console.log('ボタンがクリックされました');
});

// クリックイベントを作成
const clickEvent = new Event('click');

// イベントを手動でディスパッチ
button.dispatchEvent(clickEvent);

このコードを実行すると、実際にボタンをクリックしなくても、コンソールに「ボタンがクリックされました」というメッセージが表示されます。

イベントの伝播

イベントは、DOMツリーを通じて伝播します。この伝播には「キャプチャフェーズ」と「バブリングフェーズ」の2つがあります。EventTargetオブジェクトを理解する上で、この伝播のメカニズムを知ることは重要です。

キャプチャフェーズとバブリングフェーズ

イベントの伝播は、次の3つのフェーズで構成されています。

  1. キャプチャフェーズ: イベントがWindowから発生した要素まで下向きに伝播する段階
  2. ターゲットフェーズ: イベントが実際に発生した要素に到達した段階
  3. バブリングフェーズ: イベントが発生した要素からWindowまで上向きに伝播する段階

以下の例でこの伝播を示します。

// 親要素と子要素を取得
const parent = document.getElementById('parent');
const child = document.getElementById('child');

// 親要素にイベントリスナーを追加(バブリングフェーズ)
parent.addEventListener('click', function() {
  console.log('親要素がクリックされました(バブリング)');
});

// 親要素にイベントリスナーを追加(キャプチャフェーズ)
parent.addEventListener('click', function() {
  console.log('親要素がクリックされました(キャプチャ)');
}, { capture: true });

// 子要素にイベントリスナーを追加
child.addEventListener('click', function(event) {
  console.log('子要素がクリックされました');
  
  // バブリングを停止したい場合
  // event.stopPropagation();
});

上記のHTMLが次のような構造だとします。

<div id="parent">
  親要素
  <div id="child">子要素</div>
</div>

子要素をクリックした場合、次の順序でメッセージが表示されます。

  1. 「親要素がクリックされました(キャプチャ)」
  2. 「子要素がクリックされました」
  3. 「親要素がクリックされました(バブリング)」

この例から、イベントが最初に親要素からキャプチャフェーズで下に伝わり、ターゲット(子要素)に到達した後、バブリングフェーズで上に戻っていく様子がわかります。

イベント伝播の制御

イベントの伝播を制御するには、イベントオブジェクトのメソッドを使用します。

child.addEventListener('click', function(event) {
  console.log('子要素がクリックされました');
  
  // バブリングフェーズの伝播を停止
  event.stopPropagation();
  
  // キャプチャフェーズも含めた伝播を完全に停止
  // event.stopImmediatePropagation();
  
  // デフォルトの動作を防止
  // event.preventDefault();
});
  • stopPropagation(): 現在のイベントの伝播を停止します
  • stopImmediatePropagation(): 現在のイベントの伝播を停止し、同じ要素に登録された他のリスナーも実行されないようにします
  • preventDefault(): イベントのデフォルト動作(例:リンクのクリックによるページ遷移)を防止します

カスタムイベント

EventTargetインターフェースの強力な機能の一つに、カスタムイベントの作成と発火があります。これにより、独自のイベントを定義してコンポーネント間の通信を実現できます。

// カスタムイベントを作成
const customEvent = new CustomEvent('userAction', {
  detail: {
    username: 'tanaka',
    timestamp: new Date()
  },
  bubbles: true,
  cancelable: true
});

// イベントリスナーを追加
document.addEventListener('userAction', function(event) {
  console.log(`ユーザー ${event.detail.username} がアクションを実行しました`);
  console.log(`時刻: ${event.detail.timestamp}`);
});

// カスタムイベントを発火
document.dispatchEvent(customEvent);

この例では、'userAction'という名前のカスタムイベントを作成し、ユーザー名とタイムスタンプの情報をdetailプロパティに含めています。イベントリスナーを設定した後、dispatchEventメソッドでイベントを発火させています。

EventTargetの継承と実装

先述の通り、多くのDOMオブジェクトはEventTargetを継承しています。以下は、EventTargetを継承する主なオブジェクトです。

また、EventTargetを自分で実装したカスタムクラスを作成することも可能です。ECMAScript 2015(ES6)以降では、以下のように実装できます。

class MyEventTarget extends EventTarget {
  constructor() {
    super();
    this.value = 0;
  }
  
  setValue(newValue) {
    const oldValue = this.value;
    this.value = newValue;
    
    // 値が変更されたことを通知するカスタムイベント
    const event = new CustomEvent('valuechange', {
      detail: { oldValue, newValue }
    });
    
    // イベントを発火
    this.dispatchEvent(event);
  }
  
  getValue() {
    return this.value;
  }
}

// インスタンスを作成
const myTarget = new MyEventTarget();

// イベントリスナーを追加
myTarget.addEventListener('valuechange', function(event) {
  console.log(`値が ${event.detail.oldValue} から ${event.detail.newValue} に変更されました`);
});

// 値を設定してイベントを発火
myTarget.setValue(10);

この例では、EventTargetを継承したカスタムクラスを作成し、値が変更された時にイベントを発火させています。このパターンは、モデル-ビューアーキテクチャやコンポーネント間の通信において非常に有用です。

まとめ

EventTargetオブジェクトは、JavaScriptのイベント処理システムの基盤となるインターフェースです。主要なメソッドであるaddEventListenerremoveEventListenerdispatchEventを使用することで、イベントの登録、削除、発火を制御できます。

イベントの伝播メカニズム(キャプチャフェーズとバブリングフェーズ)を理解し、イベントの伝播を適切に制御することで、複雑なユーザーインターフェースを効率的に実装できます。また、カスタムイベントを活用することで、コンポーネント間の疎結合な通信が可能になります。

EventTargetの概念と使用方法を十分に理解することは、モダンなウェブアプリケーション開発において必須のスキルです。これらの知識を活用して、より洗練されたインタラクティブなウェブアプリケーションを構築してください。

附録

静的アクセサ

静的メソッド

継承関係

ObjectEventTarget

EventTargetのインスタンスプロパティ

EventTarget.prototype [ Symbol.toStringTag ]

EventTargetのインスタンスアクセサ

EventTargetのインスタンスメソッド

EventTarget.prototype.addEventListener()
EventTarget.prototype.constructor()
EventTarget.prototype.dispatchEvent()
EventTarget.prototype.removeEventListener()
カテゴリ:JavaScript
カテゴリ:JavaScript