46

我刚刚发现如果新 URL 在 IE 中是跨域的,则在window.opener打开的窗口中不可用。如何在 IE 中检测开窗器window.open

如果窗口在我的域中启动,离开它,然后返回到我的域,就会发生这种情况。我正在尝试在弹出窗口中进行社交注册(facebook、google 等)。完成后,它应该关闭新窗口并重定向开启者。

我知道 Soundcloud 正在实现这一点,但我不知道如何实现。我看到 URL 从他们的变为 Facebook,然后关闭。

从第 3 方重定向回我的网站后,我运行以下命令:

var data = {
  type : 'complete',
  destination : '<?= $destination; ?>'
};
if ( window.opener ) {
  window.opener.postMessage( JSON.stringify( data ), '*' );
  window.close();
}
else {
  alert( "Unable to find window" );
}

它在 IE 中发出警报,即使该窗口最初是我的域,然后重定向到 FB,然后重定向回我。我想可能是因为我打开我的网站并立即从 PHP 重定向,这可能是个问题。但是,即使我打开我的网站,window.location.href = 'facebookssite.com'返回时它仍然抱怨吗?

笔记

社交注册不适用于iframe. 我相信他们出于安全原因不允许使用它们。

4

6 回答 6

48

反过来做。从主(打开)窗口跟踪子弹出窗口的状态,您可以轻松知道子窗口何时导航回您的域,因此您可以再次“交谈”。但不要自行关闭子窗口。让 opener 窗口从子窗口获取结果,然后关闭它。

例如,main.html

<!DOCTYPE html>
<head>
<title>main</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<script>
window.addEventListener("message", function(ev) {
    if (ev.data.message === "deliverResult") {
        alert("result: " + ev.data.result);
        ev.source.close();
    }
});
        
function Go() {
    var child = window.open("child.html", "_blank", "height=200,width=200");
        
    var leftDomain = false;
    var interval = setInterval(function() {
        try {
            if (child.document.domain === document.domain) {
                if (leftDomain && child.document.readyState === "complete") {
                    // we're here when the child window returned to our domain
                    clearInterval(interval);
                    alert("returned: " + child.document.URL);
                    child.postMessage({ message: "requestResult" }, "*");
                }
            }
            else {
                // this code should never be reached, 
                // as the x-site security check throws
                // but just in case
                leftDomain = true;
            }
        }
        catch(e) {
            // we're here when the child window has been navigated away or closed
            if (child.closed) {
                clearInterval(interval);
                alert("closed");
                return; 
            }
            // navigated to another domain  
            leftDomain = true;
        }
    }, 500);
}
</script>
</head>
<body>
<button onclick="Go()">Go</button>
</body>

child.html

<!DOCTYPE html>
<head>
<title>child</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<script>
window.addEventListener("message", function(ev) {
    if (ev.data.message === "requestResult") {
        // ev.source is the opener
        ev.source.postMessage({ message: "deliverResult", result: true }, "*");
    }   
});
</script>
</head>
<body>
<a href="http://www.example.com">Go to example.com</a>
Then click the browser Back button when ready.
</body>

用IE10测试。

于 2013-09-14T17:10:20.223 回答
16

由于安全原因,window.opener在重定向到不同域时被删除。window.opener当您回来时,浏览器不会费心恢复。在您的情况下,您可以尝试:

1) 如果可能,请在 iframe 内进行身份验证,而不是使用重定向。

2)在您的情况下,我看到您需要将数据发布回父窗口。你可以试试这个:

在您打开的窗口中,只需存储您的data并正常关闭。

var data = {
  type : 'complete',
  destination : '<?= $destination; ?>'
};

window.hasData = true;
window.data = data;
window.close();

您的父窗口可以访问您打开的窗口并可以处理其close事件:

openedWindow.beforeunload = function (){
    //here you could access this.data or openedWindow.data because you're on the same domain
    if (this.hasData){
    }
    //Reason we have this check is because the beforeunload event fires whenever the user leaves your page for any reason including close, submit, clicking a link, ...
}

closed3) 解决方法:在父页面中使用计时器来检查openedWindow

setInterval(function(){
   if (openedWindow.closed){

   }
},1000);

4)另一种使用localStorage的解决方案,因为您在同一个域中。您的父页面可以收听该事件

window.addEventListener("storage", function(event){

}, true);

您打开的窗口代码:

var data = {
  type : 'complete',
  destination : '<?= $destination; ?>'
};

if (localStorage){
   localStorage.setItem(JSON.stringify(data));
}
window.close();
于 2013-09-10T06:38:10.640 回答
2
  1. 从您的 iframe、网页、yoursite.com ... 在 yoursite.com 上打开一个新窗口
  2. 窗口将自身重定向到 Google、Twitter 等
  3. 完成后,OAuth 重定向会将窗口返回到 yoursite.com 上的页面
  4. 新窗口,因为它与打开它的页面具有相同的来源,可以通过 window.open 进行通信
于 2013-09-05T18:05:01.110 回答
1

使用 localStorage 或 IndexedDB 在显示来自同一域的文档但彼此没有引用的窗口之间进行通信。

只需使用高速计时器检查数据,保存另一条数据以确认收到,另一个窗口可以找到并关闭它。

简而言之 - 您使用 localStorage 传递命令,甚至可以有一个库来执行此操作并在命令执行后删除命令,并发布返回值。

于 2017-12-24T07:26:31.983 回答
0

您可以使用 use window.postMessage(),它是为这个确切的场景提供的。

说明:https ://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage

于 2020-12-01T16:10:29.277 回答
-1

在我的公司,我们有不同的域,并且存在内部网站点必须获取我们的公共网站的情况(最终摆脱重复数据的维护)。在 Ben Vinegar 的启发下,我得出了这个解决方案的简单解决方案,避免了:

调用域网页(在我的情况下与外部网页同名)

本地' getInfo.php '

<?php 
      $idSp = (isset($_GET['idSp'])?$_GET['idSp']:null);
      echo file_get_contents('http://192.168.1.10/folder/getInfo.php?idSp='.$idSp);
 ?>

外部' getInfo.php '返回

 <?php  
    echo '<script>window.opener.manageDisplay('.$getRes.','.$isOK.');</script>';
    if($auto_close){ echo "<script>window.close();</script>"; }
  ?>
于 2017-02-10T09:23:40.370 回答