この記事について
今回は、Webページの模写の一環でモーダルウィンドウを実装しようとした際に起きた予期せぬ挙動とその解決方法を備忘録として残しておこうと思います。
やりたいこと、前提条件・環境など
実装したかったのは以下の2点です。
- ページ上の「ひらく」ボタンをクリックしたらウィンドウが出てくる
- ウィンドウの「とじる」ボタンかウィンドウ以外灰色の部分をクリックするとウィンドウを閉じる
使用言語はHTML、CSS、JavaScriptです。
ブラウザはGoogle Chromeを利用し、VSCodeの拡張機能であるLive Serverを利用して動作確認をしました。
やったこと
まず以下のコードを実行し動作を確認しました。
See the Pen Untitled by junpei osano (@junpei314) on CodePen.
結果
意図した通りに動いた点
- 「ひらく」ボタンをクリックするとウィンドウが表示される
- ウィンドウが表示されている際にウィンドウ以外をカバーしている灰色の部分をクリックするとウィンドウが閉じる
意図しない挙動をした点
- ウィンドウ自体をクリックするとウィンドウが閉じる
- 「とじる」ボタンをクリックしてもウィンドウが閉じない
結果を踏まえて試したこと
上記の結果を踏まえ以下のようにコードを変更したところ、うまく動作するようになりました。
See the Pen Untitled by junpei osano (@junpei314) on CodePen.
エラーの原因
結論としては意図しない挙動の2点ともバブリングが原因だということがわかりました。
- 「ウィンドウ自体をクリックするとウィンドウが閉じる」の原因
- 表示されるウィンドウの親要素に対してクリックイベントが設定されていたため、バブリングが発生しウィンドウが非表示になった
- 「とじるボタンをクリックしてもウィンドウが閉じない」の原因
- 「とじる」ボタンとその親要素にクリックイベントとして
toggle()
が設定されていた。toggle()は要素の表示と非表示を切り替えるメソッドである。「とじる」ボタンを押した際にクリックイベントのtoggle()が実行され、バブリングにより親要素のtoggle()も実行されていたため、ウィンドウが非表示にならなかった
- 「とじる」ボタンとその親要素にクリックイベントとして
上記の原因を解消するために以下の変更を行いました。
- 「とじる」ボタンとウィンドウをクリックした際のバブリングを止めるために、
e.stopPropagation();
を追加した -
toggle()
を使用せずに表示させたい要素のクリックイベントにはshow()
を、非表示にしたい要素のクリックイベントにはhide()
を使用した
まとめ
今回はバブリングが原因の意図しない挙動について紹介しました。
今回はイベントの伝播を止める形でモーダルウィンドウを実装しましたが、バブリングを止めることで起きる悪影響もあるみたいなのでバブリングを止めずに実装できる方法を模索してみようと思います。
参考文献・URL
バブリング と キャプチャリング
イベントの伝搬をキャンセルする
DOMイベントのキャプチャ/バブリングを整理する 〜 JSおくのほそ道 #017