欢迎来到我的博客文章!所有文章都是满满的前端干货,文章简明扼要。
原理:创建一个命名频道,同源页面可广播/监听消息(类似"群聊")
兼容性:Chrome 54+、Firefox 38+、Safari 15.4+、Edge 79+(不支持 IE)
限制:仅限同源页面(协议+域名+端口相同)
<script>
// 所有标签页:创建同名频道
const bc = new BroadcastChannel('my-app-channel');
// 监听消息
bc.onmessage = (event) => {
console.log('收到消息:', event.data);
};
// 发送消息(其他同源标签页都能收到)
bc.postMessage({ type: 'theme-change', theme: 'dark' });
// 关闭(页面卸载时建议调用)
window.addEventListener('unload', () => bc.close());
</script> 原理:修改 localStorage 会触发同源其他页面的 storage 事件
兼容性:IE8+ 全支持!✅(最广)
<script>
// 监听 storage 变化(仅其他页面触发,自身 setItem 不触发)
window.addEventListener('storage', (event) => {
if (event.key === 'tab-message') {
const data = JSON.parse(event.newValue);
console.log('收到消息:', data);
}
});
// 发送消息(所有同源标签页都会收到 storage 事件)
function sendMessage(data) {
localStorage.setItem('tab-message', JSON.stringify({
...data,
timestamp: Date.now() // 避免相同值不触发事件
}));
}
</script> 关键区别:"存数据" ≠ "通信"
✅ localStorage.setItem() + 监听 storage 事件
✔️ 能实现跨标签通信
原因:其他同源标签页会收到 storage 事件通知
❌ 仅 localStorage.setItem() + 轮询 getItem()
⚠️ 不能实时,体验差
原因:需主动查,有延迟、耗性能、难同步
// Tab A(发送)加时间戳确保值变化,触发 storage 事件
localStorage.setItem('tab-message', JSON.stringify({
type: 'theme-change',
theme: 'dark',
timestamp: Date.now() // 避免相同值不触发事件
}));
// Tab B(接收 — 正确写法)
window.addEventListener('storage', (event) => {
// ✅ 仅当其他页面修改 localStorage 时触发!
if (event.key === 'msg') {
const data = JSON.parse(event.newValue);
console.log('实时收到:', data); // 立刻执行,无延迟!
}
});
// Tab B(接收 — 错误写法)
// ❌ 轮询方式(不推荐!)
setInterval(() => {
const theme = localStorage.getItem('theme');
if (theme === 'dark') {
console.log('已切换暗色'); // 可能延迟数百毫秒~秒级触发
// 且无法知道是"新消息"还是"旧值残留"
}
}, 500); 原理:多个页面共享一个后台 Worker 线程,通过 port 通信
兼容性:Chrome/Firefox/Edge,Safari 不支持(iOS 全军覆没)
原理:所有页面通过 navigator.serviceWorker 与 SW 通信,SW 充当"中继"
要求:页面已注册 SW,且为 HTTPS(或 localhost)
适用场景:已是 PWA 应用,需结合缓存/离线能力
缺点:污染 URL,影响 SEO 和书签,不支持跨域
<script>
// 发送方
window.open('', 'target-tab').location.hash = '#msg=' + encodeURIComponent(data);
// 接收方(监听 hashchange)
window.addEventListener('hashchange', () => {
if (location.hash.startsWith('#msg=')) {
const msg = decodeURIComponent(location.hash.slice(5));
// 处理后清空
history.replaceState(null, '', location.pathname);
}
});
</script> 写入 IndexedDB,其他页定时读取
效率低、延迟高,不推荐,仅作备选