记录---浏览器多窗口通信有效实践总结

news/2025/1/15 17:44:40/文章来源:https://www.cnblogs.com/smileZAZ/p/18673528

🧑‍💻 写在开头

点赞 + 收藏 === 学会🤣🤣🤣

如何跨越不同窗口通信

在现代 Web 开发中,多个窗口或标签页之间的通信成为了越来越常见的需求,尤其是在应用需要同步数据、共享状态或进行实时更新的场景中。不同窗口间的通信方式有很多种,选择合适的方式可以大大提高开发效率和用户体验。本文将详细介绍几种常见的浏览器多窗口通信技术,并结合实际代码示例,分析它们的优缺点及兼容性。

1、window.postMessage的使用实践

window.postMessage 是一种用于跨域或同域窗口间安全通信的 API。通过 postMessage,我们可以轻松实现父子窗口、同域不同标签页或跨域之间的数据传递。

以下为实际运用中常用的2种用法:

1.1 iframe使用获得窗口引用

通过 window.postMessage,父页面可以与嵌套的 iframe 进行通信。关键是要正确获得 iframe 的引用,然后通过该引用发送消息

父页面 parent.html

  <button onclick="send()">向iframe窗口发送消息</button><iframe id="myIframe" src="http://localhost:5500/child.html"></iframe><script>function send() {const iframe = document.getElementById('myIframe');// 获得iframe窗口得window,向 iframe 发送消息iframe.contentWindow.postMessage('Hello from Parent', '*');}// 监听来自 iframe 的消息window.addEventListener('message', (event) => {if (event.origin === 'http://localhost:5500' && typeof event.data === "string") {console.log('来自 iframe 的消息:', event.data);}});</script>

iframe 页面 child.html
 
  <button onclick="send()">向父窗口发送消息</button><script>function send() {// 向父页面发送消息window.parent.postMessage("Hello from Child", "*");}// 监听来自父页面的消息window.addEventListener("message", (event) => {console.log("来自父页面的消息:", event.data);});</script>

 

注意:本地直接打开文件为file:// 协议,不能使用,浏览器会将 file:// 协议视为一个特殊的源,因为安全策略会无法使用

解决办法:将你的代码部署在一个本地开发服务器上(如使用 http-serverLive Server 或其他简单的 HTTP 服务器)。这样,你就可以通过 http://localhost/ 进行通信

1.2 window.open使用,获取窗口引用

通过 window.open 打开一个新的窗口或标签页时,我们可以获得新窗口的引用,并通过 postMessage 实现通信。

父页面 parent.html

  <button onclick="openWin()">打开新窗口</button><button onclick="send()">发送消息</button><script>let win = nullfunction openWin() {win = window.open('http://localhost:5500/child.html', '_blank');}function send() {// 向新窗口发送消息win && win.postMessage('Hello from Parent', '*');}// 监听来自 child 窗口的消息window.addEventListener('message', (event) => {if (event.origin === 'http://localhost:5500' && typeof event.data === "string") {window.alert('来自 child 窗口 的消息:' + event.data);}});

子页面child.html

  <button onclick="send()">向父窗口发送消息</button><script>function send() {// 向父页面发送消息window.opener.postMessage('Hello from Child', '*');}// 监听来自父页面的消息window.addEventListener("message", (event) => {if (event.origin === 'http://localhost:5500' && typeof event.data === "string") {window.alert("来自父页面的消息:" + event.data);}});</script>

  

 

兼容性:window.openpostMessage 在大多数现代浏览器中得到支持。需要注意:如果打开的窗口被浏览器阻止弹出,通信无法进行。

2、客户端存储 + 定时器实时刷新监听【不推荐】

通过客户端存储(如 cookielocalStoragesessionStorage)结合定时器(如 setIntervalrequestAnimationFrame),可以实现同源域名下不同窗口之间的通信。此方式利用定时器定时检查存储值的变化,但缺点是浪费性能资源,且数据更新不够实时

父页面 parent.html

// 父页面向 storage 写入数据
localStorage.setItem('message', 'Hello from Page');
 
子页面child.html
// 子页面 定时检查 localStorage 变化
setInterval(() => {const message = localStorage.getItem('message');if (message) {console.log('Received message:', message);}
}, 1000);

  

3、StorageEvent 事件监听

当一个页面修改了 localStorage 或 sessionStorage,其他同源的页面可以通过监听 storage 事件来获取更新。此方法适合同一域下多个页面之间的通信。

父页面 parent.html

  <button onclick="send()">向子窗口发送消息</button><script>let i = 1function send() {// 向新窗口发送消息localStorage.setItem('child-message', 'Hello from Parent' + i++);}window.addEventListener('storage', (event) => {if (event.key === 'parent-message') {window.alert(event.newValue);}});</script>

  

子页面child.html

  <button onclick="send()">向父窗口发送消息</button><script>let i = 1function send() {// 向父页面发送消息localStorage.setItem('parent-message', 'Hello from Child' + i++);}// 监听来自父页面的消息window.addEventListener('storage', (event) => {if (event.key === 'child-message') {window.alert(event.newValue);}});</script>

  

 

兼容性:StorageEvent 事件在大多数现代浏览器中都得到了支持,包括 Chrome、Firefox、Safari 和 Edge。它仅在同源的多个页面之间有效,无法跨域使用。

4、Broadcast Channel

BroadcastChannel API 允许同源的多个窗口、标签页、iframe 或 Web Worker 之间进行消息广播。这种方法非常适合同一应用中多个窗口或标签页之间的实时通信。

父页面 parent.html

  <button onclick="send()">向子窗口发送消息</button><script>function send() {// 发送消息到广播频道const channel = new BroadcastChannel('parnt-message');channel.postMessage('Hello from Parent');}// 监听广播频道的消息const channel = new BroadcastChannel('child-message');channel.addEventListener('message', (event) => {window.alert(event.data)});

  

子页面child.html

  <button onclick="send()">向父窗口发送消息</button><script>function send() {// 发送消息到广播频道const channel = new BroadcastChannel('child-message');channel.postMessage('Hello from Child');}// 监听广播频道的消息const channel = new BroadcastChannel('parnt-message');channel.addEventListener('message', (event) => {window.alert(event.data)});

  

 

兼容性:BroadcastChannel 在 Chrome、Firefox 和 Edge 中得到支持,但 Safari 目前不支持,且不适用于 IE 或较旧的浏览器版本。

5、SharedWorker

SharedWorker 是一种非常强大的技术,允许多个窗口、标签页或 iframe 共享同一个后台线程。它适用于跨窗口的实时数据共享和复杂计算任务。

如果要使 SharedWorker 连接到多个不同的页面,这些页面必须是同源的(相同的协议、host 以及端口)。

worker.js:执行指定 url 脚本的共享 web worker

// 共享线程worker.js
const ports = [];
self.onconnect = function (event) {const port = event.ports[0];ports.push(port); // 存储 port(端口)// 初始化发送消息port.postMessage('Hello from SharedWorker!');// 监听消息port.onmessage = function (e) {const index = ports.indexOf(port); // 获取当前的port的索引// const currentPort = ports[index]; // 当前端口// 向其他端口发送消息ports.forEach((item, idx) => {if (index !== idx) {item.postMessage('消息: ' + e.data);}})};
};

  

self.onconnect 监听多个页面与 SharedWorker 的连接。每当一个新的页面连接到共享工作线程时,onconnect 事件会被触发。在 onconnect 事件处理函数中,我们可以通过 event.ports[0] 获取页面连接的 port,然后通过 port 进行消息传递

在共享线程中浏览器控制台无法显示任何打印信息:

SharedWorker 是一种共享工作线程,它用于处理多个浏览器窗口或标签页之间的共享计算任务,并且运行在独立的线程中。工作线程(包括 SharedWorker)不具备浏览器的 DOM 环境

没有window对象,所以consolealert等方法都是无法使用的。

如果我们需要调试SharedWorker,可以使用调试Worker的方法,在浏览器地址栏中输入chrome://inspect/#workers,这样就可以看到当前页面中的SharedWorker

edge游览器:edge://inspect/#workers

 父页面 parent.html

    <button onclick="send()">向子窗口发送消息</button><script>// 创建 SharedWorker 实例const worker = new SharedWorker("worker.js");// 接收来自 worker 的消息worker.port.onmessage = function (event) {window.alert(event.data);};function send() {const message = "你好我是父窗口";worker.port.postMessage(message);}</script>

 

子页面child.html

    <button onclick="send()">向父窗口发送消息</button><script>// 创建 SharedWorker 实例const worker = new SharedWorker("worker.js");// 接收来自 worker 的消息worker.port.onmessage = function (event) {window.alert(event.data);};function send() {const message = "你好我是父窗口";worker.port.postMessage(message);}</script>

  

兼容性:SharedWorker 不支持 Internet Explorer,Safari 也存在某些限制,尤其是在移动设备上兼容性较差,在一些老旧浏览器中无法使用

总结

浏览器多窗口通信有多种方法可供选择,每种方法都有其适用场景。以下是各方法的优缺点总结:

 根据项目需求选择合适的通信方式,可以大大提升应用的性能和用户体验。

本文转载于:https://juejin.cn/post/7459359268523098138

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 

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

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

相关文章

python 按时间戳删除3232数组的前2列和后9列

还是雨滴谱文件,这次尝试批量处理 首先处理1个单独的txt文件#!usr/bin/env python # -*- coding:utf-8 _*- """@author:Suyue @file:raindrop.py @time:2025/01/15 {DAY} @desc: """ import numpy as np import redef process_file(input_file,…

电源中TL431及光耦的实战运用

首先了解一下TL431的基本原理;由一个运放及三极管组成;运放的应用前文略有几笔,此处未加反馈,运放只需要同相端与反相端做差在输出对应电压即可,而三极管是电压驱动;当VREF>2.5V即同相端大于反相端,输出正电压,三极管导通,当VREF<2.5V即同相端小于反相端,输出负…

在OERV也可以玩MC(下)

话接上回,上期讲述了在OERV安装HMCL的历程,这期讲讲HMCL的打包。Show openEuler:24.09 / HMCL - 开源软件构建与测试。在这个网站里,可以看到有好几个文件,这些都跟HMCL打包有关。 第一个是_service文件,这个文件用于从特定仓库里面拉取代码文件到当前平台,可以看见每个文…

JS-38 对象概述

什么是对象?对象(object)是JavaScript语言的核心概念,也是最重要的数据类型 简单说,对象就是一组“键对值”(key-value)的合集,是一种无序的复合数据集合 var user={ name:zifuchuan, age:13 };对象的每一个键名又称为属性(property),它的“键值”可以是任何数据类型…

第八届工业信息安全技能大赛全国复赛snake_wp

pwn题 snake writeup多少有点不自信,太久没做题,看到题都有点怕怕的这个程序是一个贪食蛇游戏,主程序如下: __int64 __fastcall main_4015A5(__int64 a1, __int64 a2) {int v2; // edxint v3; // ecxint v4; // er8int v5; // er9int v7; // [rsp+Ch] [rbp-4h]sub_400B6D()…

初识Spring -2025/1/12

bean的生命周期初始化容器1.创建对象(内存分配) 2.执行构造方法 3.执行属性注入(set操作) 4.执行bean初始化方法使用bean1.执行业务操作关闭/销毁容器1.执行bean销毁方法(3)关闭容器的两种方式:ConfigurableApplicationContext是ApplicationContext的子类close()方法 registerS…

Linux命令【date】格式化

作用:显示或设定系统的日期与时间 格式化

高效协作与工时优化的结合点在哪里

在信息化高速发展的今天,如何提升团队的协作效率、优化工时管理,已经成为每个企业面临的挑战。在线文档协作工具因其实时共享、多端同步、权限控制等功能,成为现代企业数字化办公的重要一环。本文将分析在线协作工具如何助力办公室团队优化工时管理,从而实现高效办公。一、…

easyexcel doRead bug

public class CarOilingRecordImportVO { /** * 油卡号 */ @ExcelProperty(value = "卡号/客户编号") @NotNull(message = "卡号/客户编号不能为空") private String cardCode; /** * 车牌号 */ @ExcelProperty(value =…

为什么人工智能会导致更大的社会不平等……至少在开始时如此

为什么人工智能会导致更大的社会不平等……至少在开始时如此 一次巨大变革的不对称性来源:作者使用GPT-4o撰写虽然每一次技术革命都创造了比毁掉的工作岗位更多的就业机会,人工智能也不会例外。然而,我们正迎来向那个世界转变的一个极其复杂的阶段。 简单来说,未来几年人工…

(二)C#同一个项目窗体应用程序复制粘贴窗体文件出现各种bug正确解决办法

事情是这样的,如上图所示,因为一个系统里面有好几个子系统,有些子系统之间的“增删查改”又是相通的,于是想通过复制相同的窗体到另外一个文件夹的时候,如果不正确引用“新项目”将会出现以上各种错误。在网上搜索了各种方式,尝试了各种办法,最后找到下面这种亲测有效的…