-
核心:
-
1.
postMessage()
方法:向其他窗口发送消息; -
2.
message
事件:监听其他窗口(postMessage)发送过来的消息;
-
获取窗口的引用
-
1. iframe:
window.frames[0]
; -
2. iframe:
contentWindow
、contentDocument
; - 3. iframe:class、id 等选择器;
-
4. 执行
window.open()
返回的窗口对象; - -------------👆父------------------------------👇子-------------
-
5. 新窗口获取原窗口:
window.opener
; -
6. message事件的回信对象:
event.source
;
文章目录
一、单向通信
1. 【打开B,B接收A的消息】
- a.html【A域】(http://aaa.com/a.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>a页面发送消息</title>
</head>
<body>
<input id="btn" type="button" value="打开 b 页面" />
<script>
var btn = document.querySelector('#btn');
btn.addEventListener('click', function() {
// 打开新窗口,并存储其引用(通过引用调用 postMessage)
var pageB = window.open('http://bbb.com/b.html', '_blank');
// 3秒后向该窗口发送消息
setTimeout(function() {
// 调用 postMessage 函数,将消息发送给 pageB
pageB.postMessage('该消息由A发送。', 'http://bbb.com/b.html');
// 第二参数为接收消息的窗口的源
// 1. 可以具体到某一个页面(url)
// 2. 或者域名(该域下的所有页面都会接收)
// 3. 或通配符 * (不限域,风险)
}, 3000);
});
</script>
</body>
</html>
- b.html【B域】(http://bbb.com/b.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>b页面接收消息</title>
<style>
.msg {
font-size: 3em;
font-weight: bold;
text-align: center;
color: red;
}
</style>
</head>
<body>
<div class="msg"></div>
<script>
var msg = document.querySelector('.msg');
// 接收消息
function receiveMessage(e) {
// 过滤掉不是从源发送来的消息
if (e.origin !== 'http://aaa.com') return;
// e.data 就是 A 页 postMessage 发送过来的内容
msg.textContent = e.data;
// e.source 是 A 窗口的引用
}
// message 事件,监听其它页面 postMessage 发送过来的消息
window.addEventListener('message', receiveMessage, false);
</script>
</body>
</html>
2. 【打开B,A接收B的消息】
- a.html【A域】(http://aaa.com/a.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>a页面接收消息</title>
<style>
.msg {
font-size: 3em;
font-weight: bold;
text-align: center;
color: red;
}
</style>
</head>
<body>
<input id="btn" type="button" value="打开 b 页面" />
<div class="msg"></div>
<script>
var btn = document.querySelector('#btn');
var msg = document.querySelector('.msg');
btn.addEventListener('click', function() {
// 打开新窗口,不向该窗口发送消息
window.open('http://bbb.com/b.html', '_blank');
});
// 接收消息
function receiveMessage(e) {
// 过滤掉不是从该源发送来的消息
if (e.origin !== 'http://bbb.com') return;
// e.data 就是 B 页 postMessage 发送过来的内容
msg.textContent = e.data;
// e.source 是 B 窗口的引用
}
// message 事件,监听其它页面 postMessage 发送过来的消息
window.addEventListener('message', receiveMessage, false);
</script>
</body>
</html>
- b.html【B域】(http://bbb.com/b.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>b页面发送消息</title>
</head>
<body>
<script>
// window.opener 就是父窗口的引用
var pageA = window.opener;
// 检测当前窗口是否通过其他页面打开(是否有父窗口)
if (pageA) {
// 3秒后向该窗口发送消息
setTimeout(function() {
pageA.postMessage('该消息由B发送。', 'http://aaa.com/a.html');
// 第二参数为接收消息的窗口的源
// 1. 可以具体到某一个页面(url)
// 2. 或者域名(该域下的所有页面都会接收)
// 3. 或通配符 * (不限域,风险)
}, 3000);
}
</script>
</body>
</html>
二、双向通信
1. 【打开B,B先接收A消息,再回复A】
- a.html【A域】(http://aaa.com/a.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>a页面</title>
<style>
.msg {
font-size: 3em;
font-weight: bold;
text-align: center;
color: blue;
}
</style>
</head>
<body>
<input id="btn" type="button" value="打开 b 页面" />
<div class="msg"></div>
<script>
var btn = document.querySelector('#btn');
var msg = document.querySelector('.msg');
btn.addEventListener('click', function() {
// 打开新窗口,并存储其引用(通过引用调用 postMessage)
var pageB = window.open('http://bbb.com/b.html', '_blank');
// 3秒后向该窗口发送消息
setTimeout(function() {
// 调用 postMessage 函数,将消息发送给 pageB
pageB.postMessage('该消息由A发送。', 'http://bbb.com/b.html');
// 第二参数为接收消息的窗口的源
// 1. 可以具体到某一个页面(url)
// 2. 或者域名(该域下的所有页面都会接收)
// 3. 或通配符 * (不限域,风险)
}, 3000);
});
// 接收消息
function receiveMessage(e) {
// 过滤掉不是从该源发送来的消息
if (e.origin !== 'http://bbb.com') return;
// e.data 就是 B 页 postMessage 发送过来的内容
msg.textContent = e.data;
// e.source 是 B 窗口的引用
}
window.addEventListener('message', receiveMessage, false);
</script>
</body>
</html>
- b.html【B域】(http://bbb.com/b.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>b页面</title>
<style>
.msg {
font-size: 3em;
font-weight: bold;
text-align: center;
color: red;
}
</style>
</head>
<body>
<div class="msg"></div>
<script>
var msg = document.querySelector('.msg');
// 用于存储父窗口的引用
var pageA = window.opener;
// 接收消息
function receiveMessage(e) {
// 过滤掉不是从该源发送来的消息
if (e.origin !== 'http://aaa.com') return;
// e.data 就是 A 页 postMessage 发送过来的内容
msg.textContent = e.data;
// e.source 是 A 窗口的引用
// console.log(e.source === pageA); // true
e.source.postMessage('B收到并立即回复。', e.origin);
}
// message 事件,监听其它页面 postMessage 发送过来的消息
window.addEventListener('message', receiveMessage, false);
</script>
</body>
</html>
2. 【打开B,A先接收B消息,再回复B】
- a.html【A域】(http://aaa.com/a.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>a页面</title>
<style>
.msg {
font-size: 3em;
font-weight: bold;
text-align: center;
color: red;
}
</style>
</head>
<body>
<input id="btn" type="button" value="打开 b 页面" />
<div class="msg"></div>
<script>
var btn = document.querySelector('#btn');
var msg = document.querySelector('.msg');
// 用于存储子窗口的引用
var pageB = null;
btn.addEventListener('click', function() {
// 打开新窗口,不立即向该窗口发送消息
pageB = window.open('http://bbb.com/b.html', '_blank');
});
// 接收消息
function receiveMessage(e) {
// 过滤掉不是从该源发送来的消息
if (e.origin !== 'http://bbb.com') return;
// e.data 就是 B 页 postMessage 发送过来的内容
msg.textContent = e.data;
// e.source 是 B 窗口的引用
// console.log(e.source === pageB); // true
e.source.postMessage('A收到并立即回复。', e.origin);
}
// message 事件,监听其它页面 postMessage 发送过来的消息
window.addEventListener('message', receiveMessage, false);
</script>
</body>
</html>
- b.html【B域】(http://bbb.com/b.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.msg {
font-size: 3em;
font-weight: bold;
text-align: center;
color: blue;
}
</style>
</head>
<body>
<div class="msg"></div>
<script>
var msg = document.querySelector('.msg');
// window.opener 就是父窗口的引用
var pageA = window.opener;
// 检测当前窗口是否通过其他页面打开(是否有父窗口)
if (pageA) {
// 3秒后向该窗口发送消息
setTimeout(function() {
pageA.postMessage('该消息由B发送。', 'http://aaa.com/a.html');
// 第二参数为接收消息的窗口的源
// 1. 可以具体到某一个页面(url)
// 2. 或者域名(该域下的所有页面都会接收)
// 3. 或通配符 * (不限域,风险)
}, 3000);
}
// 接收消息
function receiveMessage(e) {
// 过滤掉不是从该源发送来的消息
if (e.origin !== 'http://aaa.com') return;
// e.data 就是 A 页 postMessage 发送过来的内容
msg.textContent = e.data;
// e.source 是 A 窗口的引用
// console.log(e.source === pageA); // true
}
// message 事件,监听其它页面 postMessage 发送过来的消息
window.addEventListener('message', receiveMessage, false);
</script>
</body>
</html>
三、接收多个页面发送的消息
【A页接收B、C的消息】
- a.html【A域】(http://aaa.com/a.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>a页面接收消息</title>
<style>
.msg_b {
font-size: 3em;
font-weight: bold;
text-align: center;
color: red;
}
.msg_c {
font-size: 3em;
font-weight: bold;
text-align: center;
color: blue;
}
</style>
</head>
<body>
<input id="btn" type="button" value="同时打开 b、c 页面" />
<div class="msg_b"></div>
<div class="msg_c"></div>
<script>
var btn = document.querySelector('#btn');
var msg_b = document.querySelector('.msg_b');
var msg_c = document.querySelector('.msg_c');
btn.addEventListener('click', function() {
// 打开新窗口,不向该窗口发送消息
window.open('http://bbb.com/b.html', '_blank');
window.open('http://ccc.com/c.html', '_blank');
});
// 监听 B 页发送过来的消息
window.addEventListener('message', function(e) {
// 筛选出 B 发送过来的消息
if (e.origin !== 'http://bbb.com') return;
msg_b.textContent = e.data;
}, false);
// 监听 C 页发送过来的消息
window.addEventListener('message', function(e) {
// 筛选出 C 发送过来的消息
if (e.origin !== 'http://ccc.com') return;
msg_c.textContent = e.data;
}, false);
</script>
</body>
</html>
- b.html【B域】(http://bbb.com/b.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>b页面发送消息</title>
</head>
<body>
<script>
// window.opener 就是父窗口的引用
var pageA = window.opener;
// 检测当前窗口是否通过其他页面打开(是否有父窗口)
if (pageA) {
// 3秒后向该窗口发送消息
setTimeout(function() {
pageA.postMessage('该消息由B发送。', 'http://aaa.com/a.html');
// 第二参数为接收消息的窗口的源
// 1. 可以具体到某一个页面(url)
// 2. 或者域名(该域下的所有页面都会接收)
// 3. 或通配符 * (不限域,风险)
}, 3000);
}
</script>
</body>
</html>
- c.html【C域】(http://ccc.com/c.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>c页面发送消息</title>
</head>
<body>
<script>
// window.opener 就是父窗口的引用
var pageA = window.opener;
// 检测当前窗口是否通过其他页面打开(是否有父窗口)
if (pageA) {
// 3秒后向该窗口发送消息
setTimeout(function() {
pageA.postMessage('该消息由C发送。', 'http://aaa.com/a.html');
// 第二参数为接收消息的窗口的源
// 1. 可以具体到某一个页面(url)
// 2. 或者域名(该域下的所有页面都会接收)
// 3. 或通配符 * (不限域,风险)
}, 3000);
}
</script>
</body>
</html>
四、利用 postMessage 读写其他窗口的 LocalStorage
传送门:浏览器同源政策及其规避方法 / 3.4 LocalStorage
- a.html【A域】(http://aaa.com/a.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>a页读写其它页面localStorage</title>
</head>
<body>
<input id="btn" type="button" value="向B页发送消息" />
<iframe style="display: none;" src="http://bbb.com/b.html"></iframe>
<script>
var btn = document.querySelector('#btn');
var pageB = document.getElementsByTagName('iframe')[0].contentWindow;
// var pageB = window.frames[0];
// 需要发送的数据
var obj = {name: 'Jack', foo:'bar'};
// var foo = {id: 'aaa'};
btn.addEventListener('click', function() {
// key: 'storage' 是存入 localStorage 的键名,数据均存储在同一行
// 若需要存第二条 localStorage,则设置为其他 key 名,如:key: 'demo'
// 存储 localStorage(发送消息,修改数据)
pageB.postMessage(JSON.stringify({key: 'storage', method: 'set', data: obj}), 'http://bbb.com/b.html');
// pageB.postMessage(JSON.stringify({key: 'demo', method: 'set', data: foo}), 'http://bbb.com/b.html');
// 获取 localStorage(发送消息,获取数据,本页 message 监听读取)
pageB.postMessage(JSON.stringify({key: 'storage', method: "get"}), "*");
// pageB.postMessage(JSON.stringify({key: 'demo', method: "get"}), "*");
// 删除 localStorage(发送消息,删除数据)
pageB.postMessage(JSON.stringify({key: 'storage', method: "remove"}), "*");
// pageB.postMessage(JSON.stringify({key: 'demo', method: "get"}), "*");
});
function receiveMessage(e) {
if (e.origin !== 'http://bbb.com') return;
// 读取某个数据
console.log(JSON.parse(e.data).name);
// 读取所有 localStorage 数据
console.log(JSON.parse(e.data));
}
window.addEventListener('message', receiveMessage, false);
</script>
</body>
</html>
- b.html【B域】(http://bbb.com/b.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>b页存储本页localStorage</title>
</head>
<body>
<script>
var msg = document.querySelector('.msg');
// 接收消息
function receiveMessage(e) {
// 过滤掉不是从源发送来的消息
if (e.origin !== 'http://aaa.com') return;
var payload = JSON.parse(e.data);
switch (payload.method) {
case 'set':
localStorage.setItem(payload.key, JSON.stringify(payload.data));
break;
case 'get':
var parent = window.parent;
var data = localStorage.getItem(payload.key);
parent.postMessage(data, e.origin);
break;
case 'remove':
localStorage.removeItem(payload.key);
break;
}
}
// message 事件,监听其它页面 postMessage 发送过来的消息
window.addEventListener('message', receiveMessage, false);
</script>
</body>
</html>