跨文档消息
有时候也简称为 XDM
(cross-document messaging),是一种在不同执行上下文(如不同工作线程
或不同源的页面
)间传递信息的能力。例如 http://127.0.0.1:5500/child.html 上的页面想要与包含在内嵌窗格中的http://127.0.0.1:5500/child.html 上面的页面通信。在 XDM 之前,要以安全方式实现这种通信需要很多工作。XDM以安全易用的方式规范化了这个功能
父页面的部分代码
<div id='oo'>oo</div>
<div>
<iframe id="child" src="http://127.0.0.1:5500/child.html"></iframe>
</div>
<script type="text/javascript">
window.onload=function(){
window.frames[0].postMessage('getcolor','http://127.0.0.1:5500/child.html');
// let form = document.getElementById('child').contentwindow
}
</script>
子页面的部分代码
<div id="ii">hhhhh </div>
<script>
window.addEventListener('message',function(event){
console.log(event.data,event.origin,event.source === window.parent)
if(typeof event.data == 'string') {
document.getElementById("ii").innerHTML = event.data;
}
},false);
父页面上
核心方法
XDM 的核心是 postMessage()方法
。除了 XDM,这个方法名还在 HTML5 中很多地方用到过,
但目的都一样,都是把数据传送到另一个位置。
参数
postMessage()方法接收 3 个参数:消息、表示目标接收源的字符串。第二个参数对于安全非常重要,其可以限制浏览器交付数据的目标。下面来看一个例子:
let iframeWindow = document.getElementById("myframe").contentWindow;
iframeWindow.postMessage("A secret", "www.wrox.com");
最后一行代码尝试向内嵌窗格中发送一条消息,而且指定了源必须是"www.wrox.com"。 如果源匹配,那么消息将会交付到内嵌窗格;否则,postMessage()什么也不做。这个限制可以保护 信息不会因地址改变而泄露。如果不想限制接收目标,则可以给 postMessage()的第二个参数传"*", 但不推荐这么做。
接收
window 对象上会触发 message 事件。这个事件是异步触发的,因此从消息 发出到接收到消息(接收窗口触发 message 事件)可能有延迟。传给 onmessage 事件处理程序的 event
对象包含以下 3 方面重要信息。
-
data:作为第一个参数传递给 postMessage()的字符串数据。
-
origin:发送消息的文档源,例如"www.wrox.com"。(验证是谁发送的)
-
source:发送消息的文档中 window 对象的代理。
接收消息之后验证发送窗口的源是非常重要的。与 postMessage()的第二个参数可以保证数据不 会意外传给未知页面一样,在 onmessage 事件处理程序中检查发送窗口的源可以保证数据来自正确的 地方。基本的使用方式如下所示:
window.addEventListener("message", (event) => {
// 确保来自预期发送者
if (event.origin == "http://www.wrox.com") {
// 对数据进行一些处理
processMessage(event.data);
// 可选:向来源窗口发送一条消息
event.source.postMessage("Received!", "http://p2p.wrox.com");
}
});
大多数情况下,event.source 是某个 window 对象的代理,而非实际的 window 对象。因此不能 通过它访问所有窗口下的信息。最好只使用 postMessage(),这个方法永远存在而且可以调用。
注意
XDM 有一些怪异之处。首先,postMessage()的第一个参数的最初实现始终是一个字符串。后来, 第一个参数改为允许任何结构的数据传入,不过并非所有浏览器都实现了这个改变。为此,最好就是只 通过 postMessage() 发送字符串。如果需要传递结构化数据,那么最好先对该数据调用 JSON.stringify(),通过 postMessage()传过去之后,再在 onmessage 事件处理程序中调用 JSON.parse()。
1.端口和域名 2.嵌套页面没有改动