一、应用场景描述
vue,通过一个弹出的窗口A的选择内容,打开另一个弹出的窗口B,并传参给窗口B
二、文档说明
window.postMessage()
方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为https),端口号(443为https的默认值),以及主机 (两个页面的模数 Document.domain设置为相同的值) 时,这两个脚本才能相互通信。window.postMessage()
方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。从广义上讲,一个窗口可以获得对另一个窗口的引用(比如
targetWindow = window.opener
),然后在窗口上调用targetWindow.postMessage()
方法分发一个MessageEvent
消息。接收消息的窗口可以根据需要自由处理此事件 (en-US)。传递给window.postMessage()
的参数(比如message
)将通过消息事件对象暴露给接收消息的窗口。
三、总结
划重点:
- 跨源通信(也可以理解为我们常说的跨域):不同ip、不同端口、不同协议;
- 客户端之间通信
postMessage()的两个参数:
- message:它是要发送到另一个窗口的数据(字符串或对象);
- targetOrigin:它是发送消息的窗口的URL 。目标窗口的协议,端口和主机名必须与要发送的消息的此参数匹配。设置“*”将匹配任何URL,但不建议用于安全风险。
MessageEvent的四个属性:
- message 属性表示该message 的类型;
- data 属性为 window.postMessage 的第一个参数;
- origin 属性表示调用window.postMessage() 方法时调用页面的当前状态;
- source 属性记录调用 window.postMessage() 方法的窗口信息。
注:为了安全,一定要做好信息验证!
四、小案例
1.窗口通信
- 打开百度官网页面(窗口1),在浏览器的console中输入:
window.addEventListener('message',event=>{
if (event.source === 'https://www.baidu.com' && event.data.key !== '口令:宝塔镇河妖') return;
console.log(event.data.message);
event.source.postMessage({key: '口令:天王盖地虎', message: '通过!'}, 'https://www.baidu.com');
});
window.open('https://www.baidu.com')
// 窗口2中可见“通过!”
- 在新打开的百度页面(窗口2)中输入:
window.addEventListener('message',event => {
if (event.source === window.opener && event.data.key !== '口令:天王盖地虎') return;
console.log(event.data.message);
// 由于窗口1的时间监听中会有消息回复,所以这里如果需要消息回复,必须写到外面,防止死循环
// 如果有需要,这里可以关闭窗口1
// window.opener.close()
});
//(即向窗口1发送消息)
window.opener.postMessage({key: '口令:宝塔镇河妖', message: '大王叫我来巡山!'}, 'https://www.baidu.com');
// 窗口1中可见“大王叫我来巡山!”
2.iframe 通信
let myDomain = 'http://xxx.com';
let iframe = document.getElementById('myIFrame').contentWindow;
//周期性的发送消息
setInterval(function(){
let message = new Date().getTime();
console.log('发送: ' + message);
win.postMessage(message, myDomain);
},6000);
//监听消息反馈
window.addEventListener('message',event => {
if(event.origin !== 'http://yyy.com') return;
console.log('反馈: ',event.data);
},false);
let myDomain = 'http://yyy.com';
window.addEventListener('message',function(event) {
if(event.origin !== 'http://xxx.com') return;
console.log('接收: ' + event.data,event);
event.source.postMessage('ok!', event.origin); // 反馈消息原路返回
},false);
思考:两个没有因果关系的窗口是否可以使用这种方式通信?
模板选择:
解释:
这里用到了window.postMessage(),我的理解是:窗口A发出广播,需要参数a的,给我发个needA,然后打开窗口B,窗口B在渲染前,对它的发起者(window.opener)发出消息needA,然后就成功收到参数a,接下来关闭窗口A。