如何实现跨标签页通讯

在这里插入图片描述

什么是跨标签页通讯

同一浏览器,可以打开多个标签页,跨标签页通讯就是,一个标签页能够发消息给另一标签页。

有哪些实现方案

  1. localStorage (window.onstorage事件监听)
  2. BroadcastChannel(广播)
  3. ServiceWorker (代理服务线程)
  4. SharedWorker + 轮询
  5. indexedDB + 轮询
  6. cookie + 轮询
  7. window.open + window.postMessage()
  8. WebSocket + 后端服务

方案一:localStorage

基于storage事件

页面一(localStorage1.html):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>localStorage1</title>
</head>
<body>
    <h1>localStorage1</h1>
    <ul id="ul"></ul>
    <script>
        /** 更新视图*/
        function changeView(){
            const ul = document.getElementById('ul');
            ul.innerHTML = '';
            for(let i = 0; i < localStorage.length; i++){
                const key = localStorage.key(i);
                const value = localStorage.getItem(key);
                const li = document.createElement('li');
                li.textContent = `${key}: ${value}`;
                ul.appendChild(li);
            }
        }
        /** 数据更新-更新视图*/
        function changeData(key,value){
            localStorage.setItem(key,value);
            changeView();
        }
        /** 更新localStorage中数据 */
        changeData('name','张三')
        changeData('age','18')
    </script>
</body>
</html>

页面二(localStorage2.html):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>localStorage1</title>
</head>
<body>
    <h1>localStorage2</h1>
    <ul id="ul"></ul>
    <script>
        function changeView(){
            const ul = document.getElementById('ul');
            ul.innerHTML = '';
            for(let i = 0; i < localStorage.length; i++){
                const key = localStorage.key(i);
                const value = localStorage.getItem(key);
                const li = document.createElement('li');
                li.textContent = `${key}: ${value}`;
                ul.appendChild(li);
            }
        }
        changeView();
        //当localStorage发生变化时,会触发storage事件
        window.addEventListener('storage',changeView)
    </script>
</body>
</html>

方案二:BroadcastChannel

BroadcastChannel可以创建一个用于广播的通信频道,当所有页面都监听同一频道的消息时,其中某一个页面通过它发送的消息就会被其他页面接收到,前提是同源页面。

页面1(channel1.html):

 <!DOCTYPE html>
 <html lang="en">
 <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
 </head>
 <body>
    <h1>BroadcastChannel1-Tom</h1>
    <p>接收消息:</p>
    <p id="message" style="white-space: pre;"></p>
    <input type="text" name="message" id="messageInput">
    <button onclick="postMessage()">发送消息</button>
    <script>
        const messageElement = document.getElementById('message');
        const messageInput = document.getElementById('messageInput');
        const bc = new BroadcastChannel('channel');
        bc.onmessage = function(e) {
            console.log('收到消息:', e.data);
            messageElement.textContent += '\n'+e.data;
        }
        function postMessage() {
            console.log('发送消息');
            const message = messageInput.value;
            bc.postMessage(message);
            messageInput.value = '';
        }
    </script>
 </body>
 </html>

页面2(channel1.html):

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Document</title>
</head>
<body>
   <h1>BroadcastChannel2-Jerry</h1>
   <p>接收消息:</p>
   <p id="message" style="white-space: pre;"></p>
   <input type="text" name="message" id="messageInput">
   <button onclick="postMessage()">发送消息</button>
   <script>
       const messageElement = document.getElementById('message');
       const messageInput = document.getElementById('messageInput');
       const bc = new BroadcastChannel('channel');
       bc.onmessage = function(e) {
           console.log('收到消息:', e.data);
           messageElement.textContent += '\n'+e.data;
       }
       function postMessage() {
           console.log('发送消息');
           const message = messageInput.value;
           bc.postMessage(message);
           messageInput.value = '';
       }
   </script>
</body>
</html>

方案三:ServiceWorker

Service worker 本质上充当 Web 应用程序、浏览器与网络(可用时)之间的代理服务器。

sw.js文件-代理服务器

// 消息会先到达这里,然后发送到其他客户端
self.addEventListener('message', async (event)=> {
    // 首先获取所有注册了serviceWorker的客户端
    self.clients.matchAll().then((clients)=>{
        // 遍历所有客户端       
        clients.forEach((client)=>{
            // 向每个客户端发送消息
            client.postMessage(event.data);
        })
    })
});

service1.html文件-客户端1

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>service1</h1>
    <input type="text" id="content">
    <button id="bt">发送</button>
    <script>
        /**注册serviceWorker*/
        navigator.serviceWorker.register('sw.js').then(function(registration){
            console.log('service worker 注册成功');
        })
        const bt = document.getElementById('bt');
        bt.addEventListener('click',function(){
            const message = document.getElementById('content').value;
            // controller控制器发送消息
            navigator.serviceWorker.controller.postMessage(message);
        })
    </script>
</body>
</html>

service2.html文件-客户端2

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>service1</h1>
    <script>
        /**注册同一serviceWorker*/
        navigator.serviceWorker.register('sw.js').then(function(registration){
            console.log('service worker 注册成功');
        })
        //监听onmessage事件
        navigator.serviceWorker.onmessage = function(event){
            console.log('收到消息',event.data);
        }
    </script>
</body>
</html>

方案四:SharedWorker + 轮询

SharedWorkerWorker的一种,它允许你在多个页面之间共享一个Worker

shared.js(worker)

let data = "";//存储用户发送的信息
onconnect = (event) => {
    const port = event.ports[0];//获取客户端端口
    port.onmessage = (event) => {
        if (event.data==='get') {
            port.postMessage(data);//向客户端发送消息
        }else{
            data = event.data;//将用户发送的信息存储到data变量中
        }
    }
}

shared1.html(页面一)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>shared1</h1>
    <input type="text" id="content">
    <button id="btn">发送</button>
    <script>
        const btn = document.getElementById('btn');
        const content = document.getElementById('content');
        const message = document.getElementById('message')
        // 创建SharedWorker
        const shared = new SharedWorker('shared.js');
        btn.onclick = function(){
            // 向SharedWorker发送消息
            shared.port.postMessage(content.value);
            content.value = '';
        }
    </script>
</body>
</html>

shared2.html(页面二)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>shared1</h1>
    <input type="text" id="content">
    <button id="btn">发送</button>
    <script>
        const btn = document.getElementById('btn');
        const content = document.getElementById('content');
        const message = document.getElementById('message')
        // 创建SharedWorker
        const shared = new SharedWorker('shared.js');
        btn.onclick = function(){
            // 向SharedWorker发送消息
            shared.port.postMessage(content.value);
            content.value = '';
        }
    </script>
</body>
</html>

方案五:IndexedDB+轮询

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

redis在springboot项目中的应用

一&#xff0c;将查询结果放到redis中作为缓存&#xff0c;减轻mysql的压力。 只有在数据量大的时候&#xff0c;查询速度慢的时候才有意义。 本次测试的数据量为XXX. 测试代码: 功能为根据昵称进行模糊匹配。 GetMapping("/get-by-nick")public String getNickN…

【算法专题突破】--- 位运算 --- 丢失的数字(难度⭐) 只出现一次的数字 III (难度⭐⭐) 消失的两个数字(难度⭐⭐⭐)(2)

一&#xff0c;丢失的数字 1. 题目解析 题目链接&#xff1a;268. 丢失的数字 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 首先&#xff0c;我们设定一个长度为n的数组。理想情况下&#xff0c;如果这个数组是从…

机器人路径规划:基于鳑鲏鱼优化算法(Bitterling Fish Optimization,BFO)的机器人路径规划(提供MATLAB代码)

一、机器人路径规划介绍 移动机器人&#xff08;Mobile robot&#xff0c;MR&#xff09;的路径规划是 移动机器人研究的重要分支之&#xff0c;是对其进行控制的基础。根据环境信息的已知程度不同&#xff0c;路径规划分为基于环境信息已知的全局路径规划和基于环境信息未知或…

CSDN学习笔记总索引(2024)——我的创作纪念日(1024)

从2021-05-21至2024-03-19&#xff0c;我的CSDN博文学习笔记中&#xff0c;收集并展示浏览阅读&#xff0c;点赞收藏评论等数据&#xff0c;以浏览阅读量排逆序展示。 (笔记模板由python脚本于2024年03月19日 05:49:24创建&#xff0c;本篇笔记适合熟悉Python&#xff0c;对其基…

一维数组数组名的用途

大家好&#xff1a; 衷心希望各位点赞。 您的问题请留在评论区&#xff0c;我会及时回答。 一、数组名的用途 一维数组数组名的用途&#xff1a; 1、可以统计整个数组的长度。 2、可以获取数组在内存中的首地址。 二、示例代码 #include <iostream> #include <W…

亚马逊等跨境电商平台自养号测评的五个核心因素

一、安全稳定的环境系统 尽管市场上存在大量现成的系统和软件包&#xff0c;卖个软件或设备给你&#xff0c;这种基本上都没有解决风控的能力&#xff0c;因此&#xff0c;小编推荐大家还是自己掌握相关技术&#xff0c;避免过度依赖于外部资源&#xff0c;目前&#xff0c;也…

C语言救赎之路,有些鸟儿是困不住的!(其4) (逻辑运算符+函数)

什么是运算符&#xff1f;诶~&#xff0c;其实我们一直在用运算符&#xff0c;比如我们的 &#xff0c;-&#xff0c;*&#xff0c;/ 等等都是运算符。今天我们就先来讲讲运算符。这是结合我自己的理解&#xff0c;我认为自己讲的肯定比一些教科书讲的要更清楚一些&#xff0c;…

SpringBoot整合Xxl-Job

一、下载Xxl-Job源代码并导入本地并运行 Github地址:GitHub - xuxueli/xxl-job: A distributed task scheduling framework.&#xff08;分布式任务调度平台XXL-JOB&#xff09; 中文文档地址:分布式任务调度平台XXL-JOB 1.使用Idea或Eclipse导入 2.执行sql脚本(红色标记…

nfs介绍与配置

NFS 1. nfs简介 nfs特点 NFS&#xff08;Network File System&#xff09;即网络文件系统&#xff0c;是FreeBSD支持的文件系统中的一种&#xff0c;它允许网络中的计算机之间通过TCP/IP网络共享资源在NFS的应用中&#xff0c;本地NFS的客户端应用可以透明地读写位于远端NFS服…

动态规划课堂6-----回文串问题

目录 引言&#xff1a; 例题1&#xff1a;回文子串 例题2&#xff1a;回文串分割IV 例题3&#xff1a;分割回文串II 例题4&#xff1a;最长回文子序列 例题5&#xff1a;让字符串成为回文串的最小插入次数 引言&#xff1a; 回文字符串 是正着读和倒过来读一样的字符串。…

LeetCode 面试经典150题 80.删除有序数组中的重复项II

题目&#xff1a; 给你一个有序数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使得出现次数超过两次的元素只出现两次 &#xff0c;返回删除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件…

PTA——1075 链表元素分类、1105 链表合并、1110 区块反转

1075 链表元素分类 解决代码 #include<bits/stdc.h> using namespace std; struct node{int v;int next; }; map<int,node> s; vector<vector<pair<int,int>>> ans(3); vector<pair<int,int>> w; int main(){int st,n,k;cin>>…

鸿蒙Harmony应用开发—ArkTS-转场动画(组件内转场)

组件内转场主要通过transition属性配置转场参数&#xff0c;在组件插入和删除时显示过渡动效&#xff0c;主要用于容器组件中的子组件插入和删除时&#xff0c;提升用户体验。 说明&#xff1a; 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记…

短视频矩阵系统技术交付

短视频矩阵系统技术交付&#xff0c;短视频矩阵剪辑矩阵分发系统现在在来开发这个市场单个项目来说&#xff0c;目前基本上已经沉淀3年了&#xff0c;那么我们来就技术短视频矩阵剪辑系统开发来聊聊 短视频矩阵系统经过315大会以后&#xff0c;很多违规的技术开发肯定有筛选到了…

cuda多版本安装

主要参考文章&#xff1a; ubuntu 20.04下多版本cuda&cudnn下载与安装 在ubuntu上安装多个版本的CUDA&#xff0c;并且可以随时切换 1 环境检查 nvidia-smiCUDA Version:12.4表示最高支持cuda 12.4版本 nvcc -V如图所示表示系统目前版本为cuda 12.2 2 多版本cuda下载与…

深入解析Kafka中的动态更新模式

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 深入解析Kafka中的动态更新模式 前言动态更新模式的基础概念动态更新模式的概念&#xff1a;解决的问题和引入的原因&#xff1a; 原理解析与工作流程动态更新模式的工作原理和工作流程&#xff1a;示…

【MySQL】学习和总结使用列子查询查询员工工资信息

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-5odctDvQ0AHJJc1C {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

Spring-IOC容器注解方式整合三层架构

注解方式特点 //1. 完全注解方式指的是去掉xml文件&#xff0c;使用配置类 注解实现 //2. xml文件替换成使用Configuration注解标记的类 //3. 标记IoC注解&#xff1a;Component,Service,Controller,Repository //4. 标记DI注解&#xff1a;Autowired Qualifier Resource Va…

基于肤色模型(YCbCr模型)的人面定位统计算法,Matlab实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码代做/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供…

计算机视觉之三维重建(2)---摄像机标定

文章目录 一、回顾线代1.1 线性方程组的解1.2 齐次线性方程组的解 二、透镜摄像机的标定2.1 标定过程2.2 提取摄像机参数2.3 参数总结 三、径向畸变的摄像机标定3.1 建模3.2 求解 四、变换4.1 2D平面上的欧式变换4.2 2D平面上的相似变换和仿射变换4.3 2D平面上的透射变换4.4 3D…