モーダル管理を“クラスとして育てる”2日目のテーマ
2日目は、1日目で作った Modal クラスをさらに実用的にする 回です。
今日のポイントは次の3つです。
- 複数モーダルを扱えるようにクラス設計を強化する
- UI 状態制御を「より安全に・より明確に」する
- イベント伝播を深掘りし、背景クリックの誤作動を完全に防ぐ
1日目で「開く / 閉じる」「背景クリック」「ESCキー対応」を作りましたが、
2日目はそれを “アプリで使えるレベル” に引き上げます。
複数モーダルを扱うためのクラス設計
単一モーダルの限界を知る
1日目の Modal クラスは、
「1つのモーダルを管理する」ことには十分でした。
しかし、実際のアプリではこうなります。
- 設定モーダル
- プロフィール編集モーダル
- 削除確認モーダル
つまり、複数のモーダルが存在する のが普通です。
ここで問題になるのが、
- どのモーダルが開いているのか
- ESCキーを押したとき、どのモーダルを閉じるのか
- 背景クリックが別のモーダルに影響しないか
という「複数管理の難しさ」です。
解決策:ModalManager を導入する
Modal クラスは「1つのモーダルを管理する」役割に集中させ、
複数モーダルの調整は ModalManager に任せます。
class ModalManager {
constructor() {
this.modals = [];
}
register(modal) {
this.modals.push(modal);
}
closeAll() {
this.modals.forEach(m => m.close());
}
}
JavaScript深掘りポイント:責務を分けるとコードが壊れにくくなる
- Modal → 個別のモーダルの開閉・イベント
- ModalManager → 複数モーダルの調整
この分離によって、
アプリが大きくなっても破綻しにくくなります。
UI 状態制御をより安全にする
isOpen の役割を強化する
1日目では isOpen を boolean で持っていました。
this.isOpen = false;
JavaScript2日目では、これを 状態遷移の管理 に使います。
状態遷移の例
- closed → opening → opened → closing → closed
ただし、初級〜中級では
「opened / closed」だけでも十分です。
状態を getter にする
get opened() {
return this.isOpen;
}
JavaScriptこうすると、外部から
if (modal.opened) { ... }
JavaScriptと読みやすくなります。
深掘りポイント:UI 状態は“真実の源泉(Single Source of Truth)”
UI の状態は 1か所で管理する のが鉄則です。
- DOM のクラス名
- isOpen フラグ
- イベント登録の有無
これらがバラバラになると、
「見た目は開いてるのに isOpen は false」
という事故が起きます。
Modal クラスの中で
状態を一元管理する のが大切です。
背景クリック制御を“誤作動ゼロ”にする
1日目の背景クリック
this.backdrop.addEventListener("click", this.handleBackdropClick);
JavaScriptこれは基本として正しいですが、
実際のアプリでは次のような問題が起きます。
- モーダル内のスクロールが背景に伝わる
- モーダル内のクリックが誤って背景に届く
- モーダルの構造が変わると誤作動する
そこで、2日目では より安全な背景クリック制御 を作ります。
イベント伝播を深掘りする
クリックイベントの流れ
クリックは次の順で伝わります。
- 一番内側の要素(content)
- 親(modal)
- さらに親(body)
- document
これを バブリング(伝播) と呼びます。
誤作動の原因
モーダル内をクリックしたとき、
そのイベントが背景まで伝わると
「背景クリック」と誤認されて閉じてしまいます。
解決策:content 側で伝播を止める
this.content.addEventListener("click", (event) => {
event.stopPropagation();
});
JavaScript深掘りポイント:stopPropagation は“防波堤”
モーダル内のクリックは
「ここで止める」
という防波堤を作るイメージです。
これにより、
背景クリックと中身クリックが完全に分離されます。
ESC キー対応を“複数モーダル対応”にする
1日目の実装
document.addEventListener("keydown", this.handleKeydown);
JavaScriptこれは「モーダルごとに keydown を登録する」形でした。
複数モーダルがあると、
ESC を押したときに 複数の close() が走る 可能性があります。
解決策:ModalManager に ESC を集約する
class ModalManager {
constructor() {
this.modals = [];
document.addEventListener("keydown", (event) => {
if (event.key === "Escape") {
const opened = this.modals.find(m => m.opened);
if (opened) opened.close();
}
});
}
}
JavaScript深掘りポイント:イベントは“1か所で受ける”方が安全
複数のモーダルが同時に ESC を受け取ると混乱します。
ModalManager に集約することで、
- どのモーダルを閉じるか
- どの順番で閉じるか
を一元管理できます。
2日目のまとめ
今日あなたがやったことを整理するとこうなります。
- Modal クラスを「複数モーダル対応」に拡張した
- ModalManager を導入して責務を分離した
- UI 状態(isOpen)をより安全に扱えるようにした
- イベント伝播を深掘りし、背景クリックの誤作動を防いだ
- ESC キー対応を「1か所で管理する」形に改善した
どれも、実務でモーダルを扱うときに必ず必要になる考え方です。

