postmessage 在不同情况下的传参方式
基本语法
targetWindow.postMessage(message, targetOrigin, [transfer]);
targetWindow
targetWindow就是接收消息的窗口的引用。 获得该引用的方法包括:
- Window.open :通过window.open 打开的新页面会返回该页面的对象,通过这个对象就可以向其postmessage
- Window.opener : 由a页面打开b页面,b页面就可以通过window.opener 向a 页面发送消息
- HTMLIFrameElement.contentWindow: 子iframe 的window 对象
- Window.parent:子iframe 中父页面的window 对象
- Window.frames +索引值
message
message就是要发送到目标窗口的消息。 数据使用结构化克隆算法进行序列化。 这意味着我们可以将各种各样的数据对象安全地传递到目标窗口,而无需自己对其进行序列化。
需要注意的是:结构化克隆算法 并不是支持所有的数据格式的, 在vue3 项目中,其中的响应式数据对象实际是proxy 对象,这正好是结构化克隆算法不支持的?;岜ù硖崾靖枚韵蟛荒鼙豢寺?。
targetOrigin
targetOrigin就是指定目标窗口的来源,必须与消息发送目标相一致,可以是字符串“*”或URI。 *表示任何目标窗口都可接收,为安全起见,请一定要明确提定接收方的URI。
transfer
可选,是一串和 message 同时传递的 Transferable 对象。这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
父子页面传参
父页面向子页面传参:
document.querySelector('#iframe').contentWindow.postMessage(data,'*')
子页面向父页面传参:
window.parent.postMessage(data,'*')
监听方式:
window.addEventListener('message', function(d) {
console.log(d.data)
//同一个页面内可以设置多个监听,但要注意,在不使用的时候最好要把监听器卸载了
})
父页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>parent</title>
<style>
#son{
width: 100%;
height: 500px;
margin-top:20px;
padding:20px;
}
</style>
</head>
<body>
<button onclick="sendtoson()">向子页面传递参数1</button>
<div>子页面传上来的数据<span id="sc"></span></div>
<iframe id="son" src="./possmessage-son.html"></iframe>
</body>
<script type="text/javascript">
window.addEventListener('message', function(d) {
document.querySelector("#sc").innerText = d.data
})
window.addEventListener('message', function(d) {
console.log(d.data)
//同一个页面内可以设置多个监听,
})
let a = 1;
function sendtoson() {
a++
document.querySelector("#son").contentWindow.postMessage(a,'*')
}
</script>
</html>
子页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>son</title>
<style>
body{
padding: 0;
margin: 0;
}
</style>
</head>
<body>
<div>父级页面传过来的数据<span id="pc"></span></div>
<button onclick="sendtoparent()">返回数据给父级页面</button>
</body>
<script type="text/javascript">
window.addEventListener('message',function(d) {
console.log(d)
document.querySelector("#pc").innerText = d.data
})
let a = 1
function sendtoparent() {
a++;
window.parent.postMessage(a,'*')
}
</script>
</html>
不同tab 页面之间传参
有2个关键点:
- window.open 获取打开新窗口的对象
- window.opener 当前这个窗口是由那个窗口打开的
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>parent</title>
<style>
#son{
width: 100%;
height: 500px;
margin-top:20px;
padding:20px;
}
</style>
</head>
<body>
<button onclick="oooop()">打开b</button>
<button onclick="sendtoson()">向b传数据</button>
<div>b页面传上来的数据<span id="sc"></span></div>
</body>
<script type="text/javascript">
window.addEventListener('message', function(d) {
document.querySelector("#sc").innerText = d.data
})
let a = 1;
let bwindow = null
function sendtoson() {
a++
bwindow.postMessage(a,'*')
}
function oooop(){
bwindow = window.open('./b.html', '_blank')
}
</script>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>son</title>
<style>
body{
padding: 0;
margin: 0;
}
</style>
</head>
<body>
<div>父级页面传过来的数据<span id="pc"></span></div>
<button onclick="sendtoparent()">返回数据给父级页面</button>
</body>
<script type="text/javascript">
window.addEventListener('message',function(d) {
document.querySelector("#pc").innerText = d.data
})
let a = 1
function sendtoparent() {
a++;
window.opener.postMessage(a,'*')
}
</script>
</html>
在vue 项目中,postmessage 还可以作为一种跨组件的通信方式。
组件a:
window.postMessage(data,'*')
组件b:
window.addEventListener('message',function(d) {
console.log(d)
})