【前端实战】使用 BroadcastChannel API 实现跨标签页通信

一、引言

在现代 Web 应用开发中,我们常常会遇到需要在不同浏览器标签页之间进行通信的需求。例如,在一个电商应用中,用户在一个标签页中添加商品到购物车,希望在其他标签页中也能实时显示购物车的更新信息。传统的实现方式可能会依赖 localStorage 结合 storage 事件,但这种方式存在诸多限制,如性能问题、5MB 大小限制等。而 BroadcastChannel API 则为我们提供了一种更高效、更强大的跨标签页通信解决方案。

二、BroadcastChannel API 简介

BroadcastChannel API 是 HTML5 新增的一个 API,用于在同源的不同浏览器窗口、标签页、iframe 等之间进行实时通信。它具有以下优点:

  1. 更高效:不依赖 storage 事件,性能更好。
  2. 无大小限制:没有 localStorage 的 5MB 大小限制。
  3. 支持复杂数据类型:可以传输复杂的数据结构,如对象、数组等。
  4. 原生支持跨标签页通信:使用简单,易于实现。

三、兼容性表格

浏览器支持版本
Chrome54+
Firefox38+
Safari10.1+
Edge17+
Opera41+

从这个表格可以看出,BroadcastChannel API 在现代主流浏览器中都有较好的支持,如果你不需要兼容特别旧的浏览器版本,那么可以放心使用。

四、实现跨标签页通信的代码示例

1. 封装跨标签页通信类

首先,我们创建一个 TabCommunication 类来封装 BroadcastChannel API 的使用。

/*** 跨标签页通信类* 使用 BroadcastChannel API 实现* * 优点:* 1. 更高效,不依赖 storage 事件* 2. 没有 5MB 大小限制* 3. 支持复杂数据类型* 4. 原生支持跨标签页通信* * @class TabCommunication*/
class TabCommunication {constructor(channelName = 'tab_comm_channel') {this.channelName = channelName;this.channel = new BroadcastChannel(channelName);this.listeners = {};this.channel.onmessage = (event) => {const { type, data } = event.data;if (this.listeners[type]) {this.listeners[type].forEach(callback => callback(data));}};}/*** 发送消息到其他标签页* @param {string} type 消息类型* @param {*} data 消息数据*/send(type, data) {this.channel.postMessage({ type, data });}/*** 监听特定类型的消息* @param {string} type 消息类型* @param {function} callback 回调函数* @returns {function} 取消监听的函数*/on(type, callback) {if (!this.listeners[type]) {this.listeners[type] = [];}this.listeners[type].push(callback);// 返回取消监听函数return () => this.off(type, callback);}/*** 移除监听* @param {string} type 消息类型* @param {function} callback 回调函数*/off(type, callback) {if (!this.listeners[type]) return;const index = this.listeners[type].indexOf(callback);if (index !== -1) {this.listeners[type].splice(index, 1);}if (this.listeners[type].length === 0) {delete this.listeners[type];}}/*** 关闭通信通道*/close() {this.channel.close();}
}const tabComm = new TabCommunication();
export default tabComm;

2. 消息发送页面(sender.html)

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>消息发送者</title>
</head><body><div id="app"><button data-message="这是来自 sender.html 的消息1">发送消息1</button><button data-message="这是来自 sender.html 的消息2">发送消息2</button></div><script type="module">import tabComm from './tabCommunication.js';const app = document.getElementById('app');// 统一处理按钮点击app.addEventListener('click', async (e) => {if (e.target.tagName !== 'BUTTON') return;try {const message = e.target.dataset.message;await tabComm.send('message', { text: message });alert(`消息已发送: ${message}`);} catch (error) {console.error('发送消息失败:', error);alert('发送消息失败,请检查控制台');}});// 页面关闭时关闭通信通道window.addEventListener('beforeunload', () => {tabComm.close();});</script>
</body></html>

3. 消息接收页面(receiver.html)

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>消息接收者</title>
</head><body><div id="messageDisplay"></div><script type="module">import tabComm from './tabCommunication.js';const messageDisplay = document.getElementById('messageDisplay');const unsubscribe = tabComm.on('message', (data) => {messageDisplay.textContent = `收到消息: ${data.text}`;});// 页面关闭时取消监听并关闭通道window.addEventListener('beforeunload', () => {unsubscribe();tabComm.close();});</script>
</body></html>

五、代码解释

1. TabCommunication

  • 构造函数:初始化 BroadcastChannel 实例,并为 onmessage 事件添加处理函数,当接收到消息时,会根据消息类型调用相应的回调函数。
  • send 方法:用于向其他标签页发送消息,消息包含类型和数据。
  • on 方法:用于监听特定类型的消息,将回调函数添加到对应的监听器数组中,并返回一个取消监听的函数。
  • off 方法:用于移除指定类型的监听器。
  • close 方法:关闭 BroadcastChannel 实例。

2. sender.html

  • 通过按钮点击事件触发消息发送,调用 tabComm.send 方法发送消息。
  • 在页面关闭时,调用 tabComm.close 方法关闭通信通道。

3. receiver.html

  • 使用 tabComm.on 方法监听 message 类型的消息,当接收到消息时,更新页面显示。
  • 在页面关闭时,调用取消监听函数和 tabComm.close 方法取消监听并关闭通道。

六、总结

通过 BroadcastChannel API,我们可以轻松实现跨标签页的实时通信,避免了传统方法的诸多限制。在实际开发中,如果你需要在同源的不同标签页之间进行数据交互,不妨考虑使用 BroadcastChannel API。同时,要注意浏览器的兼容性问题,确保你的目标用户使用的浏览器支持该 API。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/901449.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微信小程序 - [渲染层错误] Uncaught TypeError: Cannot read property ‘D‘ of undefined

问题&#xff1a;[渲染层错误] Uncaught TypeError: Cannot read property D of undefined 解决&#xff1a; 该错误可能还是小程序的渲染模式有关系&#xff0c;查看app.json中是否有如下配置&#xff0c;删除即可&#xff0c;或者降低小程序调试基础库版本。

【MySQL高级】事务,存储引擎,索引(一)

Mysql高级 DQL查询语句 反引号 模糊查询避免%出现在开头,会造成索引失效 order by排序先后 表名列名都需要用${}&#xff0c;他们不能带’’ 去重统计数量 null的运算 分组函数会自动忽略null&#xff0c;不用对null进行处理 截取子串substr&#xff08;字段&#xff0c;下标…

面试篇 - GPT-1(Generative Pre-Training 1)

GPT-1&#xff08;Generative Pre-Training 1&#xff09; ⭐模型结构 Transformer only-decoder&#xff1a;GPT-1模型使用了一个12层的Transformer解码器。具体细节与标准的Transformer相同&#xff0c;但位置编码是可训练的。 注意力机制&#xff1a; 原始Transformer的解…

ubuntu24.04 cmake 报错 libldap-2.5.so.0 解决办法

apt cmake有毛病 换源重新安装 wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | sudo apt-key add - sudo apt-add-repository "deb https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main" sudo apt update sudo apt in…

ScholarCopilot:“学术副驾驶“

这里写目录标题 引言&#xff1a;学术写作的痛点与 AI 的曙光ScholarCopilot 的核心武器库&#xff1a;智能生成与精准引用智能文本生成&#xff1a;不止于“下一句”智能引用管理&#xff1a;让引用恰到好处 揭秘背后机制&#xff1a;检索与生成的动态协同快速上手&#xff1a…

vivo X200 Ultra前瞻系列(2):vivo X200 Ultra影像技术沟通会总结

vivo于今日(2025年4月14日)举办的“X系列蓝图影像技术沟通会”中,正式发布了vivo X200 Ultra,展示了其在移动影像领域的多项技术突破。以下是本次沟通会的核心内容总结: 1. 硬件革新:蔡司三焦段镜头与双芯架构 蔡司三大定焦大师镜头: X200 Ultra采用14mm超广角(“鹰眼”…

代码随想录第17天:二叉树

一、二叉搜索树的最近公共祖先&#xff08;Leetcode 235&#xff09; 由于是二叉搜索树&#xff0c;节点的值有严格的顺序关系&#xff1a;左子树的节点值都小于父节点&#xff0c;右子树的节点值都大于父节点。利用这一点&#xff0c;可以在树中更高效地找到最低公共祖先。 c…

C++中string库常用函数超详细解析与深度实践

目录 一、引言 二、基础准备&#xff1a;头文件与命名空间 三、string对象的创建与初始化(基础&#xff09; 3.1 直接初始化 3.2 动态初始化&#xff08;空字符串&#xff09; 3.3 基于字符数组初始化 3.4 重复字符初始化 四、核心函数详解 4.1 字符串长度相关 4.1.1 …

LanDiff:赋能视频创作,语言与扩散模型的融合力量

自从 Wan 2.1 发布以来&#xff0c;AI 视频生成领域似乎进入了一个发展瓶颈期&#xff0c;但这也让人隐隐感到&#xff1a;“DeepSeek 时刻”即将到来&#xff01;就在前几天&#xff0c;浙江大学与月之暗面联合推出了一款全新的文本到视频&#xff08;T2V&#xff09;生成模型…

【本地图床搭建】宝塔+Docker+MinIO+PicGo+cpolar:打造本地化“黑科技”图床方案

写在前面&#xff1a;本博客仅作记录学习之用&#xff0c;部分图片来自网络&#xff0c;如需引用请注明出处&#xff0c;同时如有侵犯您的权益&#xff0c;请联系删除&#xff01; 文章目录 前言宝塔安装DockerMinIO 安装与设置cploar内网穿透PicGo下载与安装typora安装总结互动…

centos-LLM-生物信息-BioGPT-使用1

参考&#xff1a; GitHub - microsoft/BioGPT https://github.com/microsoft/BioGPT BioGPT&#xff1a;用于生物医学文本生成和挖掘的生成式预训练转换器 |生物信息学简报 |牛津学术 — BioGPT: generative pre-trained transformer for biomedical text generation and mini…

高效爬虫:一文掌握 Crawlee 的详细使用(web高效抓取和浏览器自动化库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Crawlee概述1.1 Crawlee介绍1.2 为什么 Crawlee 是网页抓取和爬取的首选?1.3 为什么使用 Crawlee 而不是 Scrapy1.4 Crawlee的安装二、Crawlee的基本使用2.1 BeautifulSoupCrawler的使用方式2.2 ParselCrawler的使…

架构总览怎么写,才算工业级?

📈系统架构文档是整个项目最重要的起点,但很多人第一章就“写穿了”: 不是写得太细,就是没有重点。想要写出高质量、能协作、能传承的架构文档,这一篇会告诉你应该怎么做—— ✅ 架构总览的终极目标 明确边界、定义角色、画清数据流 别讲执行细节,别深入函数调用。 ✅ 架…

优先级队列(堆二叉树)底层的实现:

我们继续来看我们的优先级队列&#xff1a; 优先级队列我们说过&#xff0c;他也是一个容器适配器&#xff0c;要依赖我们的容器来存储数据&#xff1b; 他的第二个参数就是我们的容器&#xff0c;这个容器的默认的缺省值是vector&#xff0c;然后他的第三个参数&#xff0c;我…

GIC驱动程序分析

今天呢&#xff0c;我们就来具体的讲一下GIC的驱动源码啦&#xff0c;这个才是重点来着&#xff0c;我们来看看&#xff1a; GIC中的重要函数和结构体&#xff1a; 沿着中断的处理流程&#xff0c;GIC涉及这4个重要部分&#xff1a; CPU从异常向量表中调用handle_arch_irq&am…

java操作redis库,开箱即用

application.yml spring:application:name: demo#Redis相关配置redis:data:# 地址host: localhost# 端口&#xff0c;默认为6379port: 6379# 数据库索引database: 0# 密码password:# 连接超时时间timeout: 10slettuce:pool:# 连接池中的最小空闲连接min-idle: 0# 连接池中的最…

Cribl 通过Splunk search collector 来收集数据

今天利用Spliunk search collector 来收集数据啦:还是要先cribl 的官方文档: Splunk Search Collector | Cribl Docs Splunk Search Collector Cribl Stream supports collecting search results from Splunk queries. The queries can be both simple and complex, as well a…

What Was the “Game Genie“ Cheat Device, and How Did It Work?

什么是“Game Genie”作弊装置&#xff0c;它是如何工作的&#xff1f; First released in 1991, the Game Genie let players enter special codes that made video games easier or unlocked other functions. Nintendo didnt like it, but many gamers loved it. Heres wha…

位运算题目:连接连续二进制数字

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;连接连续二进制数字 出处&#xff1a;1680. 连接连续二进制数字 难度 5 级 题目描述 要求 给定一个整数 n \texttt{n} n&#xff0c;将 1 \text…

第十六届蓝桥杯Java b组(试题C:电池分组)

问题描述&#xff1a; 输入格式&#xff1a; 输出格式&#xff1a; 样例输入&#xff1a; 2 3 1 2 3 4 1 2 3 4 样例输出: YES NO 说明/提示 评测用例规模与约定 对于 30% 的评测用例&#xff0c;1≤T≤10&#xff0c;2≤N≤100&#xff0c;1≤Ai​≤10^3。对于 100…