JavaScript | 1 日 120 分 × 7 日アプリ学習:モーダルウィンドウ管理

Web APP JavaScript
スポンサーリンク

モーダル管理を“クラスとして育てる”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;
JavaScript

2日目では、これを 状態遷移の管理 に使います。

状態遷移の例

  • 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日目では より安全な背景クリック制御 を作ります。


イベント伝播を深掘りする

クリックイベントの流れ

クリックは次の順で伝わります。

  1. 一番内側の要素(content)
  2. 親(modal)
  3. さらに親(body)
  4. 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か所で管理する」形に改善した

どれも、実務でモーダルを扱うときに必ず必要になる考え方です。

タイトルとURLをコピーしました