我打开一个弹出窗口并将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)打开,一旦关闭,我就再也看不到警报了。知道为什么会这样吗?
答案 0 :(得分:71)
如前所述,相同的原始策略会阻止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间隔设置检查器功能。然后,该函数检查窗口对象是否存在并将其closed属性设置为false。如果其中任何一个不成立,这意味着窗口(可能)已关闭,我们应该触发'closeCallback函数'回调。
此功能适用于所有现代浏览器。前一段时间,Opera在从其他域上的窗口检查属性时导致错误 - 因此try..catch块。但我现在已经测试了它,看起来它的效果还不错。
我们使用这种技术为不通过SDK(ehem ... Twitter ... ehem)支持它们的网站创建“facebook-style”登录弹出窗口。这需要一些额外的工作 - 我们无法从Twitter本身获得任何消息,但是Oauth将我们重新引导回我们的域,然后我们能够将一些数据放入弹出窗口对象中,这些数据可以从开启者访问。然后在close回调函数中,我们解析了这些数据并显示了实际结果。
此方法的一个缺点是在窗口关闭后调用回调。嗯,这是我能够通过跨域政策实现的最佳目标。
答案 1 :(得分:2)
您可以收听开启窗口的'焦点'事件,当用户关闭弹出窗口时会触发该事件。
答案 2 :(得分:1)
不幸的是,您尝试跨域进行通信,这是JavaScript same origin policy禁止的。你必须使用服务器端代理或其他一些丑陋的黑客来解决它。
您可以尝试在网站上创建一个在iframe中加载外部网站的页面。然后,您可以弹出该页面并听取它卸载。
答案 3 :(得分:1)
我将@ThomasZ's回答与this one结合起来设置间隔限制(不想使用setTimeout)。
示例(在Typescript中,匿名声明,以免丢失对&#34的引用;这"):
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