概要
イベントとは、“操作への反応”ではなく“構造の変化を伝播させるトリガー”である。
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とロジックを接続する設計上のインターフェース”である。