我从另一个域启动一个 URL,然后向它发送消息
const child = window.open("http://urlfromanotherdomain.com");
child.postMessage("you cant handle the message", "*");
在我启动的子窗口中,JavaScript 代码按如下方式注册其兴趣:
window.onmessage = function(ev) {window.console.log(ev);}
问题在于,有时在子窗口中需要运行太多代码才能注册兴趣,以至于无法收到发布的消息。
如何可靠地知道跨域子窗口已准备好接收消息?我尝试注册 child.onload,但由于它是跨域而不会触发。还有什么像传递参数给window.open一样可以保证消息的传递吗?
可能相关的其他信息:
- 我使用的是 Chrome 62 版本。
- 我最终得到跨域窗口的真正原因是因为我想确保在子窗口中获得一个新的渲染线程,因为它正在完成的渲染非常繁重。如果我使其同源,Chrome 似乎会重用渲染器进程,从而重用相同的线程。
我没有找到直接执行此操作的方法。困难在于无法侦听跨域窗口上的事件,因此没有直接的方法可以知道它何时完成加载并准备好接受您发布的消息。
一个快速的解决方法是使用超时:
var child = window.open( url, winId );
setTimeout( function(){
child.postMessage(data, url);
}, 1000);
当然,如果孩子加载速度真的很慢,这种方式就不能保证。
如果您有权访问子代码,则可以使用上面的“setInterval”并继续调用 postMessage,直到子代码使用“event.source.postMessage()”返回消息,如postMessage 的 MDN 页面 https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage。父级还需要设置一个消息监听器。一旦家长收到消息,您就可以清除间隔。我还会设置一个限制,以便间隔在一定次数的尝试后停止运行。
如果您无法访问子代码,还有另一种方法,即使用 iFrame。一旦有了 iframe,您就可以知道它何时完成加载(即使它是从不同的域加载的)。这就是我让它工作的方式:
- 使用 js、css、html 创建一个新的 html 页面,如下所示,并将其命名为“child-container.html”:
window.loadChildApp = function(url, json, title){
window.document.title = title;
var iframe = document.querySelector('#myIframe');
iframe.src = url;
document.querySelector('#loadingDiv').style.display = 'none';
iframe.addEventListener('load', function(){
iframe.contentWindow.postMessage(JSON.stringify(json), url);
});
}
#myIframe{
height: 100%;
width: 100%;
border: none;
margin: none;
}
#loadingDiv{
height: 100%;
width: 100%;
margin: auto;
padding: none;
}
<div id="loadingDiv">Loading ... </div>
<iframe id="myIframe" >
-
在父页面中,打开子容器 html,附加一个加载侦听器。当它加载时,您调用 loadChildApp 函数,该函数将完成加载 iframe 的实际工作,等待它完成,然后发布消息。
let win = window.open( 'child-container.html', key );
win.addEventListener('load', function () {
win.loadChildApp(url, data, title);
});
这种技术的一个小缺点是孩子的真实标题和 URL(在地址栏中)不会向用户显示。他们只会看到您提供的标题和 child-container.html 的 url
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)