ページを離れた際に呼ばれるブラウザイベントについて
まとめ
ユーザーがページを離れた際にユーザーの動作をブロックしたいわけでなければvisibilitychange
が最適である。
特にモバイルでの動作を想定している場合、visibilitychange
はホーム画面への移動や画面 OFF、別アプリの移動などでも呼ばれるため、ユーザーがページを離れたことを検知するのに適している。
ページの非表示ではなく、ページが実際にアンロードされることを検知したい場合はpagehide
を利用した方が適している。
ユーザーの動作を止めたい場合はbeforeunload
を使うしかないが、iOS Safari では利用できず、他のモバイル環境で完璧に動作するわけではない。またモバイルでなくても、ユーザーの操作がなければダイアログは表示されない。
unload
は廃止が計画されており利用すべきではない。
動作確認
以降の文章で調査・検証などの表現をしている場合、次のページを Chrome 129、Edge 129、Safari 18、iOS Safari 18 で動作確認をしている。
https://react-ts-itkkda.stackblitz.io/
このページを 2 つのタブで開き、片方でページを閉じるなどを行うともう片方にログが送信される仕組みになっている。
大雑把な仕組みは次のようになっている。
const channel = new BroadcastChannel("...");
useEffect(() => { const controller = new AbortController(); channel.addEventListener("message", saveLogger, { signal: controller.signal, }); document.addEventListener("visibilitychange", postLog, { signal: controller.signal, }); window.addEventListener("pagehide", postLog, { signal: controller.signal, }); window.addEventListener("beforeunload", posyLog, { signal: controller.signal, }); return () => { controller.abort(); };}, []);
ページを離れた際に呼ばれるブラウザイベント
次のようなイベントが存在する。
beforeunload
pagehide
visibilitychange
unload
ページを閉じようとした場合、上から下の順にイベントが呼ばれる。
詳しくはPage Lifecycle APIを参照。
unload
イベント
利用すべきでない。
- 非推奨かつ廃止が計画されているため利用すべきでない。
- このイベントがリッスンされている場合、BFCache が妨げられる。
beforeunload
イベント
iOS Safari で動作させたい場合は、機能しない。 積極的に使うべきではなく、ユーザーが入力途中の場合のみイベントリスナーを登録するようにすべき。
- ドキュメントがアンロードされる直前に呼ばれる。
- ページを閉じようとした際にダイアログを表示できる。
- iOS Safari では利用できない。
- event.preventDefault()を呼ぶことで表示できるようになる。
- event.returnValue に何らかの値を渡す必要はない。
- 検証したところ、無くてもダイアログは表示された。
- 以前は event.returnValue に文字列を渡すことで任意のメッセージを表示できる環境が存在した。
- 現在は、ブラウザ固有のメッセージを表示することしかできない。
- 現在は、event.returnValue 自体が非推奨になっている。
- ユーザーの操作がない場合もダイアログは表示されない。
window.alert()
やwindow.confirm()
などの実行を無視する。- iOS Safari で呼ばれていない。
- Can I useを見ると、イベント自体はサポートしているが event.preventDefault()による有効化をサポートしていないだけであるように見えるが、実際に検証したところ呼ばれていない。
- Chrome や Edge などでは、event.preventDefault()を実行しなくとも呼ばれる。
- このイベントがリッスンされている場合、BFCache が妨げられる。
- そのため、常にリッスンするような実装は避けるべき。
pagehide
イベント
ページのアンロード時に何かを実行したい場合に適している。
しかし、beforeunload
と異なり、ユーザーが入力中に離脱することを防ぐような使い方は出来ない。
- セッション履歴で現在のページを非表示にすると呼ばれる。
- Chrome で検証したところ、beforeunload の後に呼ばれていた。
unload
やbeforeunload
のように BFCache などブラウザのキャッシュが妨げられることはない。- そのためページのアンロードを検知する方法としては、最適であると MDN で紹介されている。
- このイベントは
beforeunload
とは異なり、イベントをキャンセルすることは出来ない。 window.alert()
などの実行は無視される。- 以前 Safari で
visibilitychange
にバグがあったため、pagehide
を推奨する記事が多い。
visibilitychange
イベント
ユーザーのセッション終了を検知するイベントとしては最善として MDN などでは紹介されている。
beforeunload
と異なり、ユーザーが入力中に離脱することを防ぐような使い方は出来ない。
- ページの表示非表示が切り替わった際に呼ばれる。
- モバイルでは、ホーム画面への移動や画面 OFF、別アプリの移動などでも呼ばれる。
- document.visibilityState または document.hidden を利用してページの表示/非表示を識別できる。
window.alert()
などの実行は無視されない。- ただし実行タイミングが異なり、
beforeunload
のダイアログのような使い方は出来ない。 - ページを閉じる場合は実行されず、タブを切り替えた場合は、タブを元に戻すとダイアログが表示される。
- ただし実行タイミングが異なり、
pagehide
と同様に、イベントをキャンセルすることは出来ない。pagehide
と同様に、BFCache などブラウザのキャッシュが妨げられることはない。- iOS Safari 14.5 以前では、
visibilitychange
がページ遷移時に発火しないバグがあった。- そのためか、
beforeunload
の代わりにpagehide
を推奨する記事が多い。
- そのためか、