javascript Javascript检测加载另一个域的关闭弹出窗口
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15694567/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Javascript detect closing popup loaded with another domain
提问by Zorrocaesar
I am opening a popup window and attaching an onbeforeunload event to it like this:
我正在打开一个弹出窗口并将 onbeforeunload 事件附加到它,如下所示:
win = window.open("http://www.google.com", "", "width=300px,height=300px");
win.onbeforeunload = function() {
//do your stuff here
alert("Closed");
};
If I leave the URL empty, the new popup opens with "about:blank" as the address but when I close it, I see the alert.
如果我将 URL 留空,新弹出窗口会以“about:blank”作为地址打开,但当我关闭它时,我会看到警报。
If I open in as you see it (with an external URL), once it's closed, I cannot see the alert anymore. Any idea why this is happening?
如果我按照您看到的方式打开(使用外部 URL),一旦关闭,我就再也看不到警报了。知道为什么会这样吗?
回答by Tomasz Struczyński
As mentioned, same origin policy prevents Javascript from detecting such events. But there's a quite simple solution which allows you to detect closure of such windows.
如前所述,同源策略会阻止 Javascript 检测此类事件。但是有一个非常简单的解决方案可以让您检测此类窗口的关闭情况。
Here's the JS code:
这是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;
};
What it does: it creates new window with provided parameters and then sets the checker function with 1s interval. The function then checks if the window object is present and has its closed property set to false. If either ot these is not true, this means, that the window is (probably) closed and we should fire the 'closeCallback function' callback.
它的作用:它使用提供的参数创建新窗口,然后以 1 秒的间隔设置检查器功能。然后,该函数检查窗口对象是否存在并将其关闭属性设置为 false。如果这些都不为真,这意味着窗口(可能)已关闭,我们应该触发“closeCallback 函数”回调。
This function should work with all modern browsers. Some time ago Opera caused errors when checking properties from windows on other domains - thus the try..catch block. But I've tested it now and it seems it works quite ok.
此功能应该适用于所有现代浏览器。前一段时间,Opera 在检查其他域上的 Windows 属性时导致错误 - 因此 try..catch 块。但是我现在已经对其进行了测试,它似乎工作得很好。
We used this technique to create 'facebook-style' login popups for sites which doesn't support them via SDK (ehem... Twitter... ehem). This required a little bit of extra work - we couldn't get any message from Twitter itself, but the Oauth redireced us back to our domain, and then we were able to put some data in popup window object which were accessible from the opener. Then in the close callback function we parsed those data and presented the actual results.
我们使用这种技术为不通过 SDK 支持它们的站点创建“facebook 风格”登录弹出窗口(呃……推特……呃)。这需要一些额外的工作 - 我们无法从 Twitter 本身获取任何消息,但是 Oauth 将我们重定向回我们的域,然后我们能够将一些数据放入可从开启程序访问的弹出窗口对象中。然后在关闭回调函数中我们解析这些数据并呈现实际结果。
One drawback of this method is that the callback is invoked AFTER the window has been closed. Well, this is the best I was able to achieve with cross domain policies in place.
这种方法的一个缺点是回调是在窗口关闭后调用的。嗯,这是我在实施跨域策略的情况下能够实现的最好结果。
回答by Andrew
You could listen to the 'focus' event of the opener window which fires when the user closes the popup.
您可以收听当用户关闭弹出窗口时触发的打开窗口的“焦点”事件。
回答by barakbd
I combined @ThomasZ'sanswer with this oneto set an interval limit (didn't want to use setTimeout).
我将@ThomasZ 的答案与这个答案结合起来设置间隔限制(不想使用 setTimeout)。
Example (in Typescript, declared anonymously so as not lose reference to "this"):
示例(在 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
回答by chrx
Unfortunately, you're trying to communicate across domains which is prohibited by JavaScript's same origin policy. You'd have to use a server-side proxy or some other ugly hack to get around it.
不幸的是,您正在尝试跨域进行通信,这是 JavaScript 的同源策略所禁止的。您必须使用服务器端代理或其他一些丑陋的黑客来绕过它。
You could try creating a page on your site that loads the external website in an iframe. You could then pop open that page and listen for it to unload.
您可以尝试在您的网站上创建一个页面,在 iframe 中加载外部网站。然后,您可以弹出打开该页面并聆听它卸载。