浏览器多标签页通信方案

实现同源标签页之间数据通信的多种方法

问题

如何在浏览器的多个标签页之间实现数据通信?

解答

Broadcast Channel API

用于同源页面之间的广播通信,某个页面发送的消息会被其他页面监听到。

// 页面 A:创建频道并发送消息
const channel = new BroadcastChannel('my_channel');
channel.postMessage('Hello from Page A');

// 页面 B:监听消息
const channel = new BroadcastChannel('my_channel');
channel.onmessage = (event) => {
  console.log('Received:', event.data);
};

注意:仅支持同源页面,无法跨域通信。

localStorage

利用浏览器多标签共享的存储空间实现通信(sessionStorage 是会话级的,每个标签独立)。

// 页面 A:写入数据
localStorage.setItem('message', JSON.stringify({ text: 'Hello', time: Date.now() }));

// 页面 B:监听变化
window.addEventListener('storage', (event) => {
  if (event.key === 'message') {
    const data = JSON.parse(event.newValue);
    console.log('Received:', data);
  }
});

SharedWorker

可被多个同源 window 共享的 Worker 线程。

// 创建 shared-worker.js
self.addEventListener('connect', (event) => {
  const port = event.ports[0];
  port.onmessage = (e) => {
    // 广播给所有连接的页面
    port.postMessage(e.data);
  };
});

// 页面中使用
const worker = new SharedWorker('shared-worker.js');
worker.port.start();
worker.port.postMessage('Hello');
worker.port.onmessage = (event) => {
  console.log('Received:', event.data);
};

WebSocket

通过服务器中转实现全双工通信,支持跨域。

const ws = new WebSocket('ws://example.com');

ws.onopen = () => {
  ws.send('Hello from this tab');
};

ws.onmessage = (event) => {
  console.log('Received:', event.data);
};

postMessage

适用于有依赖关系的页面(如 window.open 打开的页面或 iframe 嵌入的页面)。

// 页面 A:打开页面 B
const pageB = window.open('https://example.com/pageB.html');
pageB.postMessage('Hello from A', 'https://example.com');

// 页面 B:接收并回复
window.addEventListener('message', (event) => {
  if (event.origin !== 'https://example.com') return;
  
  console.log('Received:', event.data);
  // 回复消息
  event.source.postMessage('Hello from B', event.origin);
});

postMessage 的第一个参数是消息内容(可序列化对象),第二个参数是目标源('/' 表示同源,'*' 表示所有页面)。

通过定时检查 Cookie 变化实现通信(不推荐,资源浪费)。

// 页面 A:轮询检查
let lastValue = document.cookie;
setInterval(() => {
  const currentValue = document.cookie;
  if (currentValue !== lastValue) {
    console.log('Cookie changed');
    lastValue = currentValue;
  }
}, 1000);

// 页面 B:修改 Cookie
document.cookie = 'message=Hello';

关键点

  • Broadcast Channel API 是最简单的同源通信方案,但兼容性需注意
  • localStorage 配合 storage 事件可实现简单的跨标签通信
  • postMessage 需要页面间有引用关系(window.open 或 iframe)
  • WebSocket 可跨域通信,但需要服务器支持
  • Cookie + 定时器方案性能差,不推荐使用