postMessage介绍
Window.postMessage()这个方法主要来解决两个不同页面的脚本跨源通信。
postMessage用法
otherWindow.postMessage(message,targetOrigin,[transfer])
-
message:表示我们需要传递的信息,这个数据会被结构化克隆算法序列化,可以使用JSON.stringify()方法对对象参数序列化。
-
targetOrigin:表示我们需要传数据的窗口(iframe等),这个可以是同源,也可以是不同源。
-
transfer 【可选参数】
是一串和message 同时传递的 Transferable对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
来个🌰
- 父页面初始化信息
<h1>This is parent window</h1>
<input type="text" class="inp">
<button class="send">发送信息到子页面(child-iframe)</button>
<div class="contents">
<p>接收到其他ifram的信息</p>
<ul class="messages">
</ul>
</div>
<iframe src="http://127.0.0.1:60056/child.html" frameborder="3" class="child-iframe" height="600" width="800"></iframe>
<script>
// 父页面监听message事件,接受其他iframe发送的消息
window.addEventListener('message', e => {
// 我们需要的信息都在这个回调函数中的参数 e 中
if (e.origin !== 'http://127.0.0.1:8080') { // 验证对方的身份
return
}
const box = document.querySelector('.messages')
box.innerHTML += `<li> 收到新的信息:${e.data}, 来自于${e.origin}</li>`;
});
// 子iframe的实例
const win = document.querySelector('.child-iframe').contentWindow
// 绑定我们的点击事件
document.querySelector('.send').addEventListener('click', () => {
const msg = document.querySelector('.inp').value
let msgtest={
name:123,
age:20,
hash:'id=12138&type=search'
}
// 第二参数可以使用*,也可以是iframe的URL地址,建议不要使用* ,使用准确的地址
win.postMessage(msgtest, 'http://127.0.0.1:59726/child.html')
document.querySelector('.inp').value = ''
})
</script>
参数e的属性列表
- 子页面初始化信息
<h1>This is iframe child page</h1>
<input type="text" class="inp">
<button class="send">发送信息到父页面</button>
<div class="contents">
<p>接收到的信息</p>
<ul class="messages">
</ul>
</div>
<script>
// 监听父页面的消息
let parentWin=null
window.addEventListener('message', e => {
if (e.origin !== 'http://127.0.0.1:60056') { // 验证对方的身份
return
}
// 发送详细窗口的window对象引用,调用对象postMessage方法实现父子页面的通信,当然也可以使用window.parent来通信
parentWin = e.source
const box = document.querySelector('.messages')
box.innerHTML += `<li>接收到新的信息:${e.data}-${e.data.age}, 来自于${e.origin}</li>`
})
// 绑定子页面的事件
document.querySelector('.send').addEventListener('click', () => {
const msg = document.querySelector('.inp').value
let msgtest={
name:123,
age:20,
mes:'我是子页面的信息'
}
window.parent.postMessage(msgtest, 'http://localhost:8080')
document.querySelector('.inp').value = ''
})
</script>
这两页面分别启动在不同的服务端口下,来模拟跨域场景。
postMessagge优势
- 可以实现跨文本档、多窗口、跨域消息传递。
- 允许来自不同源的脚本采用异步方式进行有限的通信。
postMessage不足
-
当父级页面刷新,message信息就不在了
-
传输数据的局限
-
RegExp对象的lastIndex字段不会被保留 -
原形链上的属性也不会被追踪以及复制
-
传输需要拿到另一窗口的实例
-
数据类型报错DATA_CLONE_ERROR
-
数据为对象的存在循环引用会报错
-
对象数据存在function的会报错
-
传输DOM结点也会报错
-
-
传输数据详情: 请点击这个
使用注意
- 需要传递消息的窗口需要嵌在父窗口中,
- 父传子:需要拿到子页面的window,本文中是使用iframe.contentWindow
- 子传父:需要拿到父页面的window,因为子页面嵌入在父页面中,则父页面的window就是子页面中window.parent
- 传递时,需要等待子页面加载完成才能发送信息.
- 任何窗口可以在任何其他窗口访问此方法,在任何时间,无论文档在窗口中的位置,向其发送消息。 因此,用于接收消息的任何事件监听器必须首先使用origin和source属性来检查消息的发送者的身份
- 当发送窗口包含
javascript:或data:URL时,origin属性的值是加载URL的脚本的