23

我正在打开一个弹出窗口并将 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),一旦关闭,我就再也看不到警报了。知道为什么会这样吗?

4

4 回答 4

72

如前所述,同源策略会阻止 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;
};

它的作用:它使用提供的参数创建新窗口,然后以 1s 的间隔设置检查器功能。然后该函数检查窗口对象是否存在并将其关闭属性设置为 false。如果其中任何一个不正确,这意味着窗口(可能)已关闭,我们应该触发“closeCallback 函数”回调。

此功能应适用于所有现代浏览器。前段时间 Opera 在从其他域的窗口检查属性时导致错误 - 因此 try..catch 块。但是我现在已经对其进行了测试,它似乎工作得很好。

我们使用这种技术为那些不通过 SDK 支持的网站创建了“facebook 风格”的登录弹出窗口(ehem...Twitter...ehem)。这需要一些额外的工作——我们无法从 Twitter 本身获得任何消息,但 Oauth 将我们重定向回我们的域,然后我们能够将一些数据放入可从打开器访问的弹出窗口对象中。然后在关闭回调函数中,我们解析这些数据并呈现实际结果。

此方法的一个缺点是在窗口关闭后调用回调。好吧,这是我能够通过跨域策略实现的最佳效果。

于 2013-07-19T10:47:09.907 回答
2

您可以收听打开窗口的“焦点”事件,该事件在用户关闭弹出窗口时触发。

于 2013-12-02T15:46:53.530 回答
1

不幸的是,您正在尝试跨域进行通信,这被 JavaScript 的同源策略所禁止。您必须使用服务器端代理或其他一些丑陋的黑客来绕过它。

您可以尝试在您的网站上创建一个页面,在 iframe 中加载外部网站。然后,您可以打开该页面并听它卸载。

于 2013-03-29T04:18:26.573 回答
1

我将@ThomasZ 的答案与这个答案结合起来设置了一个间隔限制(不想使用 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  
于 2017-10-30T01:42:46.410 回答