概要
DOMイベントは「要素をクリックすれば発火する」だけのものではない。
それは**“階層構造に沿って伝播し、任意のフェーズでハンドリング・制御できる柔軟な設計構造”**である。
JavaScriptでは、DOMイベントは「キャプチャリング → ターゲット → バブリング」の3段階で伝播する。
しかしこの伝播モデルを明確に理解しないまま stopPropagation()
を使うと、UIの挙動が意図せず崩壊するリスクを孕む。
本稿では、イベント伝播のフェーズと設計的な制御戦略、伝播停止・委譲設計のあるべき姿を解説する。
1. イベント伝播モデルの基本:3フェーズ構造
1. キャプチャリングフェーズ(親 → 子)
2. ターゲットフェーズ(イベント発生元)
3. バブリングフェーズ(子 → 親)
parent.addEventListener('click', handler, true); // キャプチャリング
child.addEventListener('click', handler); // バブリング
- ✅
true
を渡すとキャプチャフェーズで処理 - ✅
false
または未指定だとバブリングフェーズで処理
2. stopPropagation() と stopImmediatePropagation() の違い
element.addEventListener("click", (e) => {
e.stopPropagation(); // このイベントが親に伝播しなくなる
});
element.addEventListener("click", (e) => {
e.stopImmediatePropagation(); // 同じ要素の他のリスナも止まる
});
メソッド | 効果 |
---|---|
stopPropagation() |
親要素への伝播を停止 |
stopImmediatePropagation() |
同一要素内の他のリスナも含めすべて停止 |
- ✅ 基本は
stopPropagation()
- ❌ 同一ノードの他リスナを潰したい場合以外で
stopImmediatePropagation()
は使わない
3. イベント委譲設計と伝播の利点を活かす
document.body.addEventListener("click", (e) => {
if (e.target.matches(".item")) {
handleClick(e.target);
}
});
- ✅ 動的に追加される要素でも処理可能
- ✅ イベントバブリングの性質を活かした柔軟な設計
4. 伝播を止めるべきではないケース
- ❌ 「クリックが多重に反応する」からといってむやみに
stopPropagation()
を使う - ❌ UIの親要素がクリックに反応しない原因を
stopPropagation()
で誤魔化す
→ ✅ 真に必要な箇所(モーダルの閉じる制御やドラッグ操作の境界など)に限定する
5. 設計例:モーダルの外側クリックで閉じるが、内側クリックでは伝播を防ぐ
modalOverlay.addEventListener("click", closeModal);
modalContent.addEventListener("click", (e) => e.stopPropagation());
- ✅ モーダル外部クリックで閉じる
- ✅ 内部要素の操作で閉じない(伝播を止める)
設計判断フロー
① 本当に伝播を止める必要があるか?(意図と構造を明確に)
② 複数のイベントが重なって発火していないか?(stopより設計整理を優先)
③ 委譲設計は導入できるか?(動的要素を一括処理する構造)
④ stopImmediatePropagation() を使っていないか?(最終手段)
⑤ 伝播フェーズを意識して addEventListener の第三引数を明示しているか?
よくあるミスと対策
❌ 親要素がイベントを検知しなくなって原因が不明
→ ✅ 子要素で stopPropagation()
が仕込まれていることを確認
❌ 全イベントを document
に直接バインドして委譲しようとして複雑化
→ ✅ コンテナレベルで粒度の合ったイベント委譲を設計する
❌ .stopPropagation()
を多用してイベント伝播の全体像が破綻
→ ✅ 伝播構造を前提にUIの設計自体を見直す
結語
イベントバブリング / キャプチャリング制御とは、
「伝播を止める」ことではない。
それは**“DOM構造を前提としたイベントの流れを理解し、UI制御を構造として安全に設計する”**ための戦略である。
-
stopPropagation()
は例外的に使用すべき防御構造 - 委譲設計とバブリングはイベント効率化のための本質的な手段
-
addEventListener
の第三引数は「伝播フェーズ」を明示するための設計要素
JavaScriptにおけるイベント伝播の設計とは、
“階層と流れを読み解き、UI動作を構造としてコントロールする戦略的設計行為”である。