浏览器窗口之间通信

227 阅读2分钟

1. window.postMessge()

这是一种安全的跨域通信方式。你可以使用window.postMessage()方法发送消息到另一个窗口,不论这两个窗口是否同源。接收消息的窗口需要添加message事件监听来处理接收到的数据。

优点:
  • 安全性较高,因为发送方明确指定接收方。
  • 可以跨域通信。
缺点:
  • 需要对目标窗口的引用。
  • 需要处理消息的接收和处理。
发送消息:
// otherWindow是对其他窗口的引用,例如通过window.open获取或是iframe.contentWindow
otherWindow.postMessage("hello there!", 'https://target-origin.example.com');
接收消息
window.addEventListener('message', (event)=>{
    // 可以通过event.origin检查发送消息的窗口是否是预期的来源
    if(event.origin === 'https://source-origin.example.com') {
        console.log('Received message:', event.data);
    }else{
    // 来自未预期的消息应当被忽略
        return;
    }
})

2. localStorage+事件监听

localStorage的更改会触发storage事件,该事件在除了更改localStorage的窗口之外的同源窗口中被触发。这可以用来实现同源窗口的简单通信。

优点:
  • 简单易用,不需要目标窗口的引用。
  • 可以在同一域名下的不同页面之间通信。
缺点:
  • 数据存储在本地,可能会有安全风险。
  • 存储空间有限。
发送消息
localStorage.setItem('message', 'Hello, World');
接收消息
window.addEventListener('storage', (event)=>{
    if(event.key === 'message') {
        console.log('Received message:', event.newValue)
    }
});

3. BroadcastChannel API

BroadcastChannel API可以用于同源窗口、标签页或iframe之间的简单通信。

优点:
  • 简易性:通过少量的代码就可以实现跨标签页或窗口的消息传递。
  • 安全性:只有来自相同源的标签页才能互相通信。
缺点:
  • 兼容性:所有的浏览器中并不普遍支持BroadcastChannel API,尤其是旧浏览器。
  • 同源限制:需要同源才能通信
创建通道并发送消息
const channel = new BroadcastChannel('channel_name');
channel.postMessage('Hello, World!');
接收消息
const channel = new BroadcastChannel('channel_name');
channel.onmessage = (event)=>{
    console.log('Received message:', event.data);
};

4. 使用共享的Web Workers

如果你的应用需要在不同窗口或标签页间进行复杂的后台处理和通信,可以使用Web Workers(特别是SharedWorker)。SharedWorker允许多个脚本(即使他们是不同窗口、标签页或者iframe中的)与同一个worker进程通信

SharedWorker中:
// sharedworker.js
onconnect = function(e){
    var port = e.ports[0];
    port.onmessage = function(event){
        // 处理接收到的消息
        port.postMessage('Received your message:'+event.data);
    };
}

在主脚本中:
var myWorker = new SharedWorker('sharedworker.js');
myWorker.port.start();

myWorker.port.postMessage('Hello, World!');
myWorker.port.onmessage = function(event){
    console.log(event.data);
};