两个窗口之间互相通信
1、使用postMessage
*window.postMessage()* 方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为https),端口号(443为https的默认值),以及主机 (两个页面的模数 Document.domain设置为相同的值) 时,这两个脚本才能相互通信。*window.postMessage()* 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。
从广义上讲,一个窗口可以获得对另一个窗口的引用(比如 targetWindow = window.opener),然后在窗口上调用 targetWindow.postMessage() 方法分发一个 MessageEvent 消息。接收消息的窗口可以根据需要自由处理此事件。传递给 window.postMessage() 的参数(比如 message )将通过消息事件对象暴露给接收消息的窗口。
otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow
其他窗口的一个引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。
message
将要发送到其他 window的数据。它将会被结构化克隆算法序列化。这意味着你可以不受什么限制的将数据对象安全的传送给目标窗口而无需自己序列化。[1]
targetOrigin
通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示无限制)或者一个URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。这个机制用来控制消息可以发送到哪些窗口;例如,当用postMessage传送密码时,这个参数就显得尤为重要,必须保证它的值与这条包含密码的信息的预期接受者的origin属性完全一致,来防止密码被恶意的第三方截获。如果你明确的知道消息应该发送到哪个窗口,那么请始终提供一个有确切值的targetOrigin,而不是*。不提供确切的目标将导致数据泄露到任何对数据感兴趣的恶意站点。
***transfer*** 可选
是一串和message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
例如A页面打开B页面,A页面向B页面发送消息,或者B页面向A页面发送消息。
A页面
在React中实现过程
componentDidMount(){
window.addEventListener('message',(e)=>{ // 监听B页面发送的消息
if(e.data?.message){ // 单页面应用通过传递的data判断我要接收的窗口信息
console.log(e.data.message) // 打印=> 我准备好接收数据了
// 接收到B页面发送的数据后,同时向B页面发送一条数据(防止B页面还没挂载监听消息就开始发送,导致B页面收不到消息)
this.newWindow.postMessage({
name:'page_a',
message:'我来自a页面'
},
'*') // 这里*可以换成B页面的路径,指定向B页面发送消息
}
})
}
this.newWindow = window.open('/message','message') // 由某个事件触发
B页面
在React中componentDidMount生命周期中执行
componentDidMount(){
window.addEventListener('message',(event)=>{
console.log('消息来源',event)
})
window.opener.postMessage({message:'我准备好接收数据了'},'*') //向A页面发送一条数据,告诉B。
}
2、使用监听storage
A页面
这里描述B页面向A页面发送数据
在React中实现过程
componentDidMount(){
window.addEventListener('storage',(e)=>{ // 监听storage变更
})
}
this.newWindow = window.open('/message','message') // 由某个事件触发
B页面
在React中componentDidMount生命周期中执行
componentDidMount(){
localStorage.setItem('page_b', '我是B页面') // 改变storage。
}
注:如果A页面要接收到指定页面发送的数据,需要根据storage里面的数据做相应的判断,同时B页面需要更改storage。
3、使用webSocket
两个页面需要监听相同的websocket服务,通过服务中转消息
const ws = new WebSocket('ws://localhost:3000/');
// Web Socket 已连接上,使用 send() 方法发送数据
ws.onopen = function() {
// 这里用一个延时器模拟事件
setInterval(function() {
ws.send('客户端消息');
},2000);
}
// 这里接受服务器端发过来的消息
ws.onmessage = function(e) {
console.log(e.data)
}