window.postMessage HTML5新特性
跨文档通信 API (Cross-document messaging)
这个API为window对象添加了一个 window.postMessage
方法,允许跨窗口通信,不论这两个窗口是否同源。
例如,父窗口 http://aaa.com
向子窗口 http://bbb.com
发送消息,调用 postMessage
方法就可以了。
var popup = window.open('http://bbb.com', 'title')
popup.postMessage('Hello World!', 'http://bbb.com')
该方法第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源,也可以设为 *
表示不限制域名,向所有窗口发出
子窗口向父窗口发送消息的写法类似:
window.opener.postMessage('Nice to meet you', 'http://aaa.com')
父窗口和子窗口都可以通过监听 message
事件来获取对方的消息
window.addEventListener('message', function (e) {
console.log()
}, false)
message
事件的事件对象 event
,提供以下三个属性。
- event.source 发送消息的窗口
- event.origin 消息所来自的网址
- event.data 消息内容
子窗口通过 event.source
属性引用父窗口,然后发送消息。
window.addEventListener('message', receiveMessage)
function receiveMessage(event) {
event.source.postMessage('Nice to see you!', '*')
}
event.origin
属性可以过滤不是发送给本窗口的消息
window.addEventListener('message', receiveMessage)
function receiveMessage(event) {
if (event.origin !== 'http://aaa.com') return;
if (event.data === 'Hello World') {
event.source.postMessage('Hello', event.origin)
} else {
console.log(event.data)
}
}
localStorage
通过 window.postMessage
,读写其他窗口的localStorage也成为了可能下面是一个主窗口写入iframe子窗口的localStorage的例子
window.onmessage = function (e) {
if (e.origin !== 'http://bbb.com') {
return;
}
var payload = JSON.parse(e.target)
localStorage.setItem(payload.key, JSON.stringify(payload.data))
}
父窗口发送消息的代码如下:
var win = document.getElementByTagName('iframe')[0].contentWindow;
var obj = { name: 'Jack' }
win.postMessage(JSON.stringify({key: 'storage', data: obj}), 'http://bbb.com')
加强版的子窗口接收消息的代码如下:
window.onmessage = function (e) {
if (e.origin !== 'http://bbb.com') return;
var payload = JSON.parse(e.target)
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, 'http://aaa.com')
break;
case 'remove':
localStorage.removeItem(payload.key)
break;
}
}
加强版的父窗口发送消息代码如下:
var win = document.getElementByTagName('iframe')[0].contentWindow;
var obj = { name: 'Jack' };
win.postMessage(JSON.stringify({key: 'storage', method: 'set', data: obj}), 'http://bbb.com');
win.postMessage(JSON.stringify({key: 'storage', method: 'get'}), '*')
window.onmessage = function (e) {
if (e.origin !== 'http://aaa.com') return;
console.log(JSON.parse(e.data).name)
}
基本思路为:
父窗口打开一个子窗口,并返回出了一个窗口对象(可调用此api的也可能是一个其他窗口的引用),用这个窗口对象给这个子窗口自身发送一个消息,目标域填写子窗口的域
子窗口获取到父窗口的引用(window.parent
),然后用这个引用给父窗口自身发送消息,目标域填写父窗口的。