核心想法是找到一个通用的第三方。这个第三方可以同时联系到标签一、标签二。(同样的逻辑,可以参考 vuex 或 pinia)

- BroadcastChannel
- 适用场景: 同源的多个 Tab 需要简单高效的消息广播
- 实现原理: BroadcastChannel 提供了一个发布/订阅模型,允许同源页面间传递消息。
Tab1 发送消息:
js
const channel = new BroadcastChannel('my_channel');
channel.postMessage('Hi from Tab 1');
Tab2 发送消息:
js
const channel = new BroadcastChannel('my_channel');
channel.onmessage = (event)=>{
console.log('Received message:', event.data);
}
- 优点: 简单易用,支持多 Tab 广播。
- 限制: 需要页面同源,浏览器支持范围有限(现代浏览器支持良好)。
- LocalStorage + StorageEvent
- 适用场景: 同源页面间低频、简单的状态同步。
- 实现原理: localStorage 数据更新时,其他 Tab 会触发 storage 事件,页面可监听到数据变化。
Tab1 写入消息:
js
localStorage.setItem('key', 'hi from Tab 1');
Tab2 监听变化:
js
window.addEventListener('storage', (event)=>{
if(event.key === 'key'){
console.log('Received message:', event.newValue);
}
})
- Service Worker
- 适用场景: 需要多个 Tab 与后台服务共享信息或实现双向通信
- 实现原理: 通过 Service Worker 的消息通道,Tab 可以与 Service Worker 通信,Service Worker 也可以作为中间层实现多个 Tab 间的消息转发。
Tab 发送消息到 Service Worker:
js
navigator.serviceWorker.controller.postMessage('hi from Tab');
Service Worker 监听消息并广播:
js
self.addEventListener('message', (event)=>{
self.clients.matchAll().then(clients =>{
clients.forEach(client => client.postMessage(event.data));
})
})
Tab 接收消息:
js
navigator.serviceWorker.addEventListener('message', (event) => {
console.log('Received message:', event.data);
});
- SharedWorker
- 适用场景: 需要多个同源 Tab 长连接并共享状态。
- 实现原理: SharedWorker 允许多个 Tab 共享一个 Worker 线程,并通过消息通道通信。
SharedWorker文件(worker.js):
js
onconnect = function(event) {
const port = event.ports[0];
port.onmessage = (e) => {
console.log('Received from Tab:', e.data);
port.postMessage('Message received in Worker');
};
};
Tab 使用 SharedWorker:
js
const worker = new SharedWorker('worker.js');
worker.port.onmessage = (event) => {
console.log('Received from Worker:', event.data);
};
worker.port.postMessage('hi from Tab');
- 优点: 支持双向通信,性能较好。
- 限制: 需要同源,较少应用于简单场景,现代浏览器支持较好。
- WebSocket
- 适用场景: 跨域或需要实时通信的复杂场景(不仅限于浏览器 Tab 通信)。
- 实现原理: 多个 Tab 通过 WebSocket 连接同一个服务端,服务端转发消息。
js
const socket = new WebSocket('wss://example.com/socket');
socket.onmessage = (event) => {
console.log('Received message:', event.data);
};
socket.send('hi from Tab');
- 优点: 不受同源限制,支持实时通信。
- 限制: 需要服务端支持,需额外开发和维护。
- PostMessage + window.opener
- 适用场景: 当 Tab 通过 window.open 打开的,支持父窗口与子窗口之间的通信。
- 实现原理: 通过 postMessage 方法向特定窗口发送消息。
父窗口发送消息给子窗口:
js
const childWindow = window.open('child.html');
childWindow.postMessage('hi from Parent', '*');
子窗口接收消息:
js
window.addEventListener('message', (event) => {
console.log('Received message:', event.data);
});
- 优点: 灵活支持跨域通信。
- 限制: 仅限于父子窗口,不能广播到多个Tab。