BroadcastChannel
目录
- 1. 简介
- 2. 基本使用
- BroadcastChannel 的 name 参数说明
- 3. 完整示例:使用相同的 name → test-channel
- 4. 主要特点
- 5. 实际应用场景
- 6. 注意事项
1. 简介
- BroadcastChannel 是一个用于==同源页面==之间进行通信的 Web API。
- 它允许同源的不同浏览器窗口、标签页、iframe 之间发送和接收消息。
2. 基本使用
// 创建或连接到一个广播频道
const channel = new BroadcastChannel('channel-name');
// 发送消息
channel.postMessage('Hello from page A!');
// 接收消息
channel.onmessage = (event) => {
console.log('Received:', event.data);
};
// 关闭连接
channel.close();
BroadcastChannel 的 name 参数说明
[!danger] 只要使用相同的 channel name,就会连接到同一个广播频道
BroadcastChannel 不需要在不同 Tab 之间共享变量
。
- 每个 Tab 只需要使用相同的 channel name 创建自己的 BroadcastChannel 实例即可。
// 在任意 Tab 中,只要使用相同的 channel name ('my-channel'),
// 就可以创建一个连接到同一广播频道的实例
const channel = new BroadcastChannel('my-channel');
演示
假设我们有三个 HTML 文件,分别在不同的 Tab 中打开:
page1.html
<!-- page1.html -->
<!DOCTYPE html>
<html>
<body>
<h1>Page 1</h1>
<button onclick="sendMessage()">Send Message from Page 1</button>
<div id="messages"></div>
<script>
// 每个页面创建自己的 channel 实例
const channel = new BroadcastChannel('my-channel');
function sendMessage() {
channel.postMessage({
from: 'Page 1',
content: 'Hello from Page 1!',
time: new Date().toLocaleTimeString()
});
}
// 监听消息
channel.onmessage = (event) => {
const messagesDiv = document.getElementById('messages');
messagesDiv.innerHTML += `
<p>Received: ${event.data.content} (from ${event.data.from} at ${event.data.time})</p>
`;
}
</script>
</body>
</html>
page2.html
<!-- page2.html -->
<!DOCTYPE html>
<html>
<body>
<h1>Page 2</h1>
<button onclick="sendMessage()">Send Message from Page 2</button>
<div id="messages"></div>
<script>
// 在另一个页面创建一个新的 channel 实例,使用相同的名称
const channel = new BroadcastChannel('my-channel');
function sendMessage() {
channel.postMessage({
from: 'Page 2',
content: 'Hello from Page 2!',
time: new Date().toLocaleTimeString()
});
}
channel.onmessage = (event) => {
const messagesDiv = document.getElementById('messages');
messagesDiv.innerHTML += `
<p>Received: ${event.data.content} (from ${event.data.from} at ${event.data.time})</p>
`;
}
</script>
</body>
</html>
page3.html
<!-- page3.html -->
<!DOCTYPE html>
<html>
<body>
<h1>Page 3</h1>
<button onclick="sendMessage()">Send Message from Page 3</button>
<div id="messages"></div>
<script>
// 在第三个页面同样创建一个 channel 实例
const channel = new BroadcastChannel('my-channel');
function sendMessage() {
channel.postMessage({
from: 'Page 3',
content: 'Hello from Page 3!',
time: new Date().toLocaleTimeString()
});
}
channel.onmessage = (event) => {
const messagesDiv = document.getElementById('messages');
messagesDiv.innerHTML += `
<p>Received: ${event.data.content} (from ${event.data.from} at ${event.data.time})</p>
`;
}
</script>
</body>
</html>
关键点说明
-
独立实例
- 每个 Tab 都创建自己的 BroadcastChannel 实例
- 实例之间是相互独立的
- 不需要共享变量
-
连接机制
// 只要使用相同的 channel name,就会连接到同一个广播频道 const channel = new BroadcastChannel('my-channel');
-
自动连接
- ==浏览器会自动处理==不同 Tab 之间的连接
- 不需要手动建立连接
- 不需要共享任何变量
-
生命周期
// 页面关闭时自动断开连接 // 也可以手动关闭 window.addEventListener('unload', () => { channel.close(); });
-
实际应用示例
// 可以封装成一个通用的消息系统 class TabCommunication { constructor(channelName = 'app-channel') { this.channel = new BroadcastChannel(channelName); this.handlers = new Map(); this.channel.onmessage = (event) => { const { type, data } = event.data; if (this.handlers.has(type)) { this.handlers.get(type)(data); } }; } send(type, data) { this.channel.postMessage({ type, data }); } on(type, handler) { this.handlers.set(type, handler); } close() { this.channel.close(); this.handlers.clear(); } } // 使用示例 const communication = new TabCommunication(); // 注册消息处理器 communication.on('userLogin', (userData) => { console.log('User logged in:', userData); }); // 发送消息 communication.send('userLogin', { id: 1, name: 'John' });
BroadcastChannel API 的设计就是基于 channel name 来建立通信的。 只要在不同的 Tab 中使用相同的 channel name 创建实例,它们就能相互通信。 这是浏览器内部实现的机制,对开发者来说是透明的。
3. 完整示例:使用相同的 name → test-channel
页面 A
// 页面 A
const channelA = new BroadcastChannel('test-channel');
// 发送消息
channelA.postMessage({
type: 'greeting',
content: 'Hello from Page A',
timestamp: Date.now()
});
// 监听消息
channelA.onmessage = (event) => {
console.log('Page A received:', event.data);
};
// 错误处理
channelA.onmessageerror = (event) => {
console.error('Error receiving message:', event);
};
// 当不再需要时关闭
// channelA.close();
页面 B
// 页面 B
const channelB = new BroadcastChannel('test-channel');
// 发送消息
channelB.postMessage({
type: 'response',
content: 'Hello back from Page B',
timestamp: Date.now()
});
// 监听消息
channelB.onmessage = (event) => {
console.log('Page B received:', event.data);
};
4. 主要特点
1. 同源策略
- 只能在同源(相同的协议、域名和端口)的页面间通信
// 只有相同源的页面才能接收到消息
// https://example.com 和 https://example.com/page2.html 可以通信
// https://example.com 和 https://other-domain.com 不能通信
2. 广播性质
- 消息会广播给所有订阅了该频道的页面
// 所有订阅了 'news-channel' 的页面都会收到消息
const newsChannel = new BroadcastChannel('news-channel');
newsChannel.postMessage('Breaking news!');
3. 支持多种数据类型
// 可以发送各种类型的数据
channel.postMessage({
text: 'Hello',
number: 123,
array: [1, 2, 3],
date: new Date(),
// 注意:不能发送函数或DOM节点
});
5. 实际应用场景
1. 多标签页数据同步
// 用户登录状态同步
const authChannel = new BroadcastChannel('auth');
// 登录成功后广播
function onLogin(userData) {
authChannel.postMessage({
type: 'login',
user: userData
});
}
// 其他标签页监听登录状态
authChannel.onmessage = (event) => {
if (event.data.type === 'login') {
updateUIWithUserData(event.data.user);
}
};
2. 主题切换同步
const themeChannel = new BroadcastChannel('theme');
// 切换主题时广播
function toggleTheme(theme) {
document.body.className = theme;
themeChannel.postMessage({ theme });
}
// 其他页面同步主题
themeChannel.onmessage = (event) => {
document.body.className = event.data.theme;
};
3. 购物车数据同步
const cartChannel = new BroadcastChannel('shopping-cart');
// 添加商品时广播
function addToCart(product) {
cart.push(product);
cartChannel.postMessage({
type: 'add',
product
});
}
// 其他标签页同步购物车
cartChannel.onmessage = (event) => {
if (event.data.type === 'add') {
updateCartUI(event.data.product);
}
};
6. 注意事项
1. 内存管理
// 在不需要时记得关闭连接
window.addEventListener('unload', () => {
channel.close();
});
2. 错误处理
channel.onmessageerror = (event) => {
console.error('消息接收错误:', event);
};
3. 兼容性检查
if ('BroadcastChannel' in window) {
// 支持 BroadcastChannel
const channel = new BroadcastChannel('test');
} else {
// 降级处理,可以使用 localStorage 等其他方式
console.log('Browser does not support BroadcastChannel');
}
BroadcastChannel 是一个强大的 API,特别适合用于需要在多个同源页面间同步数据的场景。它的使用简单直接,但要注意同源限制和适当的资源管理。