window.open
で別ウィンドウを開いたときに、そのウィンドウの開閉を監視しようとしたら少しハマりました。
シンプルにやろうとする→失敗
まずは、unload
イベントで検出しようとしました。
const w = window.open('/path/to/somewhere');
w.addEventListener('unload', () => {
console.log('unload');
}, false);
このようにすると、ウィンドウは開いたままでもunload
が出力されてしまいます。
どうしてこうなった?
じつは、window.open
を実行した場合、いったんabout:blank
が開いて、それを指定のパスに置き換える、という形で処理が進んでいきます。そして、about:blank
を上書きする際にunload
イベントが発生してしまうのです。
じゃあ、どうしようか
タイマーで監視する
window.closed
というプロパティがありますので、タイマーでこの変化を監視するような方法も考えられます。
const w = window.open('/path/to/somewhere');
const timer = setInterval(() => {
if(!w.closed) return;
clearInterval(timer);
console.log('closed');
}, 100);
半ば無理やりな方法ですが、この方法の利点としてクロスドメインでも使えるということがあります(同一生成元でない場合、w.addEventListener
を行うことはできません)。
unload
イベントでチェック
1回目のunload
は、location.href
がabout:blank
で発生しますので、それをチェックする方法も考えられます。
const w = window.open('/path/to/somewhere');
w.addEventListener('unload', () => {
if(w.location.href==='about:blank') return;
console.log('unload');
}, false);
ただし、この方法の欠点として、指定されたページが表示される前にページを閉じてしまうと、about:blank
のままでunload
イベントが発生するため、そちらと区別がつかない、ということがあります。
- ページの読み込み前に閉じた場合→
about:blank
でunload
(終わり) - ページの読み込み後に閉じた場合→
about:blank
でunload
→本来のページでunload
ということで、ページが開く前の検知は、タイマーで監視するのがいちばんわかりやすい、という印象です。