多 tab 页通信方案
不使用 WebSocket 实现浏览器多标签页之间的通信
问题
需要在本地实现一个聊天室,多个 tab 页相互通信,不能使用 WebSocket,如何实现?
解答
方案一:LocalStorage + storage 事件
LocalStorage 可以在同源的不同标签页之间共享数据。当一个标签页修改 LocalStorage 时,其他标签页会触发 storage 事件。
// 发送消息
function sendMessage(message) {
localStorage.setItem('chatMessage', JSON.stringify({
content: message,
timestamp: Date.now()
}));
}
// 接收消息
window.addEventListener('storage', (e) => {
if (e.key === 'chatMessage' && e.newValue) {
const message = JSON.parse(e.newValue);
console.log('收到消息:', message.content);
}
});
方案二:Broadcast Channel API
Broadcast Channel API 专门用于同源页面之间的通信,API 更简洁直观。
// 创建频道
const channel = new BroadcastChannel('chat_room');
// 发送消息
channel.postMessage({
user: 'User1',
content: 'Hello',
timestamp: Date.now()
});
// 接收消息
channel.onmessage = (e) => {
console.log('收到消息:', e.data);
};
// 关闭频道
channel.close();
方案三:SharedWorker
SharedWorker 可以在多个标签页之间共享一个后台线程,适合需要集中管理状态的场景。
// shared-worker.js
const connections = [];
onconnect = (e) => {
const port = e.ports[0];
connections.push(port);
port.onmessage = (event) => {
// 广播给所有连接
connections.forEach(conn => {
conn.postMessage(event.data);
});
};
};
// 页面中使用
const worker = new SharedWorker('shared-worker.js');
worker.port.start();
// 发送消息
worker.port.postMessage({ content: 'Hello' });
// 接收消息
worker.port.onmessage = (e) => {
console.log('收到消息:', e.data);
};
关键点
- LocalStorage 方案最简单,但注意
storage事件不会在当前页面触发,只在其他标签页触发 - Broadcast Channel API 是最推荐的方案,API 简洁且专为跨标签页通信设计
- SharedWorker 适合需要集中管理状态的复杂场景,但兼容性相对较差
- 这些方案仅适用于同源页面的本地通信,无法实现跨域或跨网络通信
目录