是否有一个简单的钩子来检测脚本打开的窗口是否已完成加载?基本上,我想要相当于onLoad()钩子,但我不能直接设置它 - 假设子文档是给定的,我实际上不能在其中放置我自己的任何代码.
例如,假设我有以下两个文件:
parent.html:
<html>
<head>
<title>Parent</title>
</head>
<script type="text/javascript">
var w;
function loadChild() {
w = window.open();
w.location.href="child.html";
// block until child has finished loading... how?
w.doSomething();
}
</script>
</html>
<body>
I am a parent window. <a href="javascript:loadChild()">Click me</a>.
</body>
Run Code Online (Sandbox Code Playgroud)
child.html:
<html>
<head>
<title>Child</title>
</head>
<script type="text/javascript">
function doSomething() {
alert("Hi there");
}
</script>
</html>
<body>
I am a child window
</body>
Run Code Online (Sandbox Code Playgroud)
由于设置location.href是非阻塞的,w.doSomething()因此尚未定义,并且doSomething()调用会爆炸.如何检测孩子已完成装载?
Øys*_*sen 20
如果新打开的窗口的位置是同源的,则此方法有效:
var w = window.open('child.html')
w.addEventListener('load', w.doSomething, true);
Run Code Online (Sandbox Code Playgroud)
接受的答案并没有解决原来的问题:
w = window.open();
w.location.href="child.html";
// block until child has finished loading... how?
w.doSomething();
Run Code Online (Sandbox Code Playgroud)
为了解决这个问题,我们需要更多地了解页面加载是如何在后台进行的。实际上它是异步的,因此当您编写w.location.href="child.html";并w.doSomething();立即调用时,它不会等到新页面加载。虽然浏览器开发人员很好地解决了 iframe 的加载问题,但对于子窗口却并非如此。没有用于此的 API,因此您所能做的就是编写某种解决方法。您可以做的是从子窗口的卸载事件侦听器中使用正确的延迟函数:
w.addEventListener("unload", function (){
defer(function (){
w.doSomething();
});
});
Run Code Online (Sandbox Code Playgroud)
像往常一样,客户端 js 开发,每个浏览器的工作方式完全不同。
最好的解决方案是使用 defer 函数,它会在子窗口的文档处于加载就绪状态时调用回调,您可以在其中添加加载处理程序。如果在此之前调用回调,那么在当前浏览器中,新文档尚未创建,因此加载处理程序将添加到旧文档中,稍后将被新文档替换,因此加载处理程序将迷路了。唯一的例外是 Firefox,因为该浏览器将加载处理程序添加到窗口中。如果浏览器在加载 readyState 之后调用 defer 回调,那么在当前的某些浏览器中,页面实际加载后甚至可能会有超过 2500 毫秒的延迟。我不知道为什么某些浏览器会因子窗口文档加载的某些延迟而产生如此巨大的延迟。找了一会儿,但没有找到任何答案。一些浏览器没有任何“加载”延迟,因此您所能做的就是使用“延迟”延迟,并希望最好。根据我的测试结果,基于 MessageChannel 的解决方案是最好的多浏览器“加载”延迟:
function defer (callback) {
var channel = new MessageChannel();
channel.port1.onmessage = function (e) {
callback();
};
channel.port2.postMessage(null);
}
Run Code Online (Sandbox Code Playgroud)
因此,您可以执行以下操作:
w.addEventListener("unload", function (){
// note: Safari supports pagehide only
defer(function (){
if (w.document.readyState === "loading")
w.addEventListener("load", function (){
w.doSomething();
});
else
w.doSomething();
});
});
Run Code Online (Sandbox Code Playgroud)
如果你想支持 Safari,那么你应该使用 pagehide 而不是 unload。该pagehide事件从IE 11的支持,所以如果你想支持更老的浏览器,那么你必须同时使用卸载和pagehide,只有其中一人开始延迟如果两者都可用。
var awaitLoad = function (win, cb){
var wasCalled = false;
function unloadListener(){
if (wasCalled)
return;
wasCalled = true;
win.removeEventListener("unload", unloadListener);
win.removeEventListener("pagehide", unloadListener);
// Firefox keeps window event listeners for multiple page loads
defer(function (){
win.document.readyState;
// IE sometimes throws security error if not accessed 2 times
if (win.document.readyState === "loading")
win.addEventListener("load", function loadListener(){
win.removeEventListener("load", loadListener);
cb();
});
else
cb();
});
};
win.addEventListener("unload", unloadListener);
win.addEventListener("pagehide", unloadListener);
// Safari does not support unload
});
w = window.open();
w.location.href="child.html";
awaitLoad(w, function (){
w.doSomething();
});
Run Code Online (Sandbox Code Playgroud)
如果支持 Promises 和 async 函数,那么您可以使用以下内容:
w = window.open();
await load(w, "child.html");
w.doSomething();
Run Code Online (Sandbox Code Playgroud)
但这是一个不同的故事......
怎么样
parent.html:
<html>
<head>
<title>Parent</title>
</head>
<script type="text/javascript">
var w;
function loadChild() {
w = window.open();
w.location.href="child.html";
// like this (with jquery)
$(w).ready(function()
{
w.doSomething();
});
}
</script>
</html>
<body>
I am a parent window. <a href="javascript:loadChild()">Click me</a>.
</body>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
49300 次 |
| 最近记录: |