受浏览器同源策略限制,不同协议、端口号、主机的页面一般不能通信。window.postMessage() 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。
一个窗口可以获得对另一个窗口的引用,然后在窗口上调用 targetWindow.postMessage() 方法分发一个 MessageEvent 消息。接收消息的窗口可以根据需要自由处理此事件。传递给 window.postMessage() 的参数(比如 message)将通过消息事件对象暴露给接收消息的窗口。
语法:
otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow: 其他窗口的一个引用,比如 iframe 的 contentWindow 属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。
message: 将要发送到其他 window 的数据。
targetOrigin: 指定接收消息事件的窗口,其值可以是一个URI或者字符串 "*"(表示无限制)。
transfer:可选参数,是一串和 message 同时传递的 Transferable 对象。这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
使用:
示例一: A 打开 B,B 发送数据给 A
// A 页面
window.addEventListener("message", (e) => {
console.log(e.data)
console.log(e.origin)
console.log(e.source)
})
// 自动调用open会被浏览器拦截,需要手动取消拦截
// 或者添加一个点击事件,通过手动调用来打开新窗口
window.open("http://127.0.0.1:5501/B.html", "B")
// B 页面
const msg = {
name: "B"
}
const opener = window.opener
opener.postMessage(msg, "http://127.0.0.1:5500")
// 这里讲一下targetWindow与URI之间的联系
// URI必须是opener窗口所在在的URI
// 意思就是说,如果是从 http://127.0.0.1:5500 中的某个页面将B页面打开,那么就能成功发送跨文档信息
// 如果讲此处的URI换成"*",就意味着任何网页打开B页面,都能收到B页面传输的信息
示例二: A 打开 B,并且发送数据给 B
// A 页面
<button onclick="openB()">open B</button>
const msg = {
name: "A"
}
var open = window.open("http://127.0.0.1:5501/B.html", "B")
function openB() {
open = window.open("http://127.0.0.1:5501/B.html", "B")
}
window.addEventListener("message", (e) => {
if(e.origin === "http://127.0.0.1:5501") {
open.postMessage(msg, "http://127.0.0.1:5501")
}
})
// B 页面
const opener = window.opener
opener.postMessage(msg, "http://127.0.0.1:5500")
window.addEventListener("message", (e) => {
console.log(e.data)
console.log(e.origin)
console.log(e.source)
})
示例三:在 Iframe 里父传子
// A 页面
<iframe src="http://127.0.0.1:5501/B.html" frameborder="1" id="Bframe"></iframe>
const msg = {
name: "A"
}
window.onload = () => {
// 自动调用必须放在onload中,通过事件调用则不用
// let frame = document.querySelector("#Bframe").contentWindow
let frame = window.frames[0]
frame.postMessage(msg, "http://127.0.0.1:5501")
}
// B 页面
window.addEventListener("message", (e) => {
console.log(e.data)
console.log(e.origin)
console.log(e.source)
})
示例四:在 Iframe 里子传父
// A 页面
<iframe src="http://127.0.0.1:5501/B.html" frameborder="1" id="Bframe"></iframe>
window.addEventListener("message", (e) => {
console.log(e.data)
console.log(e.origin)
console.log(e.source)
})
// B 页面
const msg = {
name: "B"
}
window.top.postMessage(msg, "http://127.0.0.1:5500")
参考:
window.postMessage - Web API 接口参考 | MDN (mozilla.org)
记录postMessage的详细使用