我从另一个域启动一个URL,然后将postMessage发送到它
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,可以保证传递消息吗?
可能相关的其他信息:
答案 0 :(得分:0)
我找不到直接执行此操作的方法。困难在于无法在跨域窗口上侦听事件,因此无法直接知道何时加载完成并准备接受您发布的消息。
一种快速的解决方法是使用超时:
var child = window.open( url, winId );
setTimeout( function(){
child.postMessage(data, url);
}, 1000);
当然,如果孩子的加载速度真的很慢,则不能保证以这种方式。
如果您有权访问子代代码,则可以使用上面的“ setInterval”并继续调用postMessage,直到子代使用“ event.source.postMessage()”返回消息为止,如MDN page for postMessage中所述。父级还需要设置一个消息侦听器。父级收到消息后,您便会清除间隔。我还会设置一个限制,以使间隔在尝试一定次数后停止运行。
如果您无法访问子代码,则还有另一种方法,涉及使用iFrame。拥有iframe后,就可以知道它何时完成加载(即使它是从其他域加载的)。这就是我的工作方式:
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);
});
此技术的一个次要缺点是不会向用户显示孩子的真实标题和网址(在地址栏中)。他们只会看到您给的标题和child-container.html的网址