1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScriptにおけるイベント設計戦略:委譲・スコープ制御・一過性イベント・カスタムイベント構造

Posted at

概要

イベントとは、“操作への反応”ではなく“構造の変化を伝播させるトリガー”である。
UIはイベントによって動的に変化し、イベントの設計はそのままインタラクションの設計である。

本稿では、DOMイベントの基本構造から委譲設計、スコープ制御、カスタムイベントの抽象化、イベント駆動設計の原則までを体系的に解説する。


1. イベントリスナーの基本構造と落とし穴

button.addEventListener('click', () => {
  console.log('Clicked');
});
  • addEventListener関数オブジェクトを渡すことが原則
  • onclick = function... では後から上書きされうる

2. イベント委譲:親に任せる設計

document.querySelector('#list').addEventListener('click', (e) => {
  if (e.target.matches('.item')) {
    console.log('Clicked item:', e.target.textContent);
  }
});
  • 動的に生成される要素でも対応可
  • ✅ リスナーを1箇所に集約でき、性能・構造ともに明瞭
  • stopPropagation() の多用は委譲を阻害する

3. スコープと伝播制御

✅ イベントバブリングの理解

parent.addEventListener('click', () => console.log('parent'));
child.addEventListener('click', (e) => {
  e.stopPropagation();
  console.log('child');
});
  • stopPropagation() → バブリング停止
  • stopImmediatePropagation() → 他の同階層リスナーも阻止
  • capture: trueキャプチャフェーズで実行

4. 一過性イベントとクリーンアップ戦略

function bindOnce(el, type, callback) {
  const handler = function (e) {
    el.removeEventListener(type, handler);
    callback(e);
  };
  el.addEventListener(type, handler);
}
  • ✅ 一度きりの処理(例:初回クリック、初期化、同意)を自己削除型リスナーで設計
  • ✅ 不要イベントの残留防止

5. カスタムイベントの発火と監視

const event = new CustomEvent('user:login', {
  detail: { userId: 'u01' },
});
document.dispatchEvent(event);
document.addEventListener('user:login', (e) => {
  console.log('ログイン検知', e.detail.userId);
});
  • ✅ 名前空間付きイベントで意図の明確化
  • detail任意の構造体を含められる
  • ✅ UIだけでなく状態通知にも使える

6. イベント駆動のドメイン設計と契約

  • ✅ 「何が発火されるか」をコード外部から見える設計にする
  • ✅ 複数イベントのマッピングを用意(例:イベントバス、PubSub)
export const EventBus = new EventTarget();
EventBus.dispatchEvent(new CustomEvent('cart:updated'));
EventBus.addEventListener('cart:updated', updateCartIcon);

→ ✅ イベント設計がドメイン知識の構造化になる


設計判断フロー

① 要素が動的に生成される? → 委譲で親に任せる

② 複数箇所で使われる? → 共通のイベント名で抽象化

③ 状態変化を検知したい? → カスタムイベント + EventBus構造

④ 一度きりのイベント? → 自己削除型リスナー

⑤ 他のイベントに影響を与える? → stopPropagationを慎重に

よくあるミスと対策

❌ 同じ要素に何度もaddEventListenerし、メモリリーク

→ ✅ 明示的にremoveEventListenerを設計に組み込む


❌ DOM構造とイベントの責務が混在し、変更に弱い構造に

→ ✅ UIとイベントの接点を分離し、コントローラ層を用意する


❌ カスタムイベントの命名がバラバラで意図不明

→ ✅ 名前空間(例:user:login, modal:close)で意味と粒度を明確に


結語

イベントとは「起こること」ではなく、
「構造の中で何を伝え、どう変化させるか」を設計する信号である。

  • 委譲によって構造を軽くし
  • カスタムイベントで意味を可視化し
  • バブリング・伝播を設計に取り込む

JavaScriptにおけるイベント設計とは、
“UIとロジックを接続する設計上のインターフェース”である。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?