web-dev-qa-db-ja.com

JavaScriptが別のドメインでロードされたポップアップを閉じることを検出する

ポップアップウィンドウを開いて、onbeforeunloadイベントを次のようにアタッチします。

win = window.open("http://www.google.com", "", "width=300px,height=300px");
win.onbeforeunload = function() {
    //do your stuff here
    alert("Closed");
};

URLを空のままにすると、新しいポップアップが開き、アドレスとして「about:blank」が表示されますが、閉じるとアラートが表示されます。

(外部URLを使用して)ご覧のとおりに開いた場合、いったん閉じると、アラートを表示できなくなります。なぜこれが起こっているのでしょうか?

22
Zorrocaesar

前述のように、同じOriginポリシーにより、JavaScriptはそのようなイベントを検出できません。しかし、そのようなウィンドウのクローズを検出できる非常にシンプルなソリューションがあります。

ここにJSコードがあります:

var openDialog = function(uri, name, options, closeCallback) {
    var win = window.open(uri, name, options);
    var interval = window.setInterval(function() {
        try {
            if (win == null || win.closed) {
                window.clearInterval(interval);
                closeCallback(win);
            }
        }
        catch (e) {
        }
    }, 1000);
    return win;
};

機能:指定されたパラメーターで新しいウィンドウを作成し、1秒間隔でチェッカー関数を設定します。次に、この関数は、ウィンドウオブジェクトが存在し、closedプロパティがfalseに設定されているかどうかを確認します。これらのいずれかが真でない場合、これはウィンドウが(おそらく)閉じられており、「closeCallback関数」コールバックを起動する必要があることを意味します。

この関数は、最新のすべてのブラウザで機能するはずです。しばらく前にOperaが他のドメインのウィンドウからプロパティをチェックするときにエラーを引き起こしました-したがって、try..catchブロックです。しかし、私はそれを今テストしましたが、かなり問題なく動作しているようです。

この手法を使用して、SDK(ehem ... Twitter ... ehem)でサポートされていないサイト用の「facebookスタイル」のログインポップアップを作成しました。これには少し余分な作業が必要でした。Twitter自体からメッセージを取得できませんでしたが、Oauthがドメインに戻ってきたため、データをポップアップに表示することができましたオープナーからアクセス可能なウィンドウオブジェクト次に、クローズコールバック関数でこれらのデータを解析し、実際の結果を表示しました。

このメソッドの1つの欠点は、ウィンドウが閉じられた後にコールバックが呼び出されることです。まあ、これは、クロスドメインポリシーを導入して実現できた最高の方法です。

71

ユーザーがポップアップを閉じたときに発生するオープナーウィンドウの 'focus'イベントをリッスンできます。

2
Andrew

私は @ ThomasZ's 回答と this one を組み合わせて間隔制限を設定しました(setTimeoutを使用したくありませんでした)。

例(TypeScriptでは、「this」への参照を失わないように匿名で宣言します):

  private _callMethodWithInterval = (url: string, callback: function, delay: number, repetitions: number) => {      
    const newWindow = window.open(url, "WIndowName", null, true);

    let x = 0;
    let intervalID = window.setInterval(() => {
      //stops interval if newWindow closed or doesn't exist
      try {
        if (newWindow == null || newWindow.closed) {
          console.info("window closed - interval cleared")
          callback();
          window.clearInterval(intervalID);
        }
      }
      catch (e) {
        console.error(`newWindow never closed or null - ${e}`)
      }
      //stops interval after number of intervals
      if (++x === repetitions) {
        console.info("max intervals reached - interval cleared")        
        window.clearInterval(intervalID);
      }
    }, delay)
  }//end _callMethodWithInterval  
1
barakbd

残念ながら、JavaScriptの 同じOriginポリシー で禁止されているドメイン間で通信しようとしています。あなたはそれを回避するためにサーバー側のプロキシまたは他のいくつかの醜いハックを使用する必要があります。

Iframeに外部Webサイトをロードするページをサイトに作成してみてください。次に、そのページをポップオープンし、アンロードするのを待ちます。

1
chrx