如何实现跨标签页通讯

news2024/9/19 10:46:45

在这里插入图片描述

什么是跨标签页通讯

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

有哪些实现方案

  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+轮询

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

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

相关文章

Redis如何设置键的生存时间或过期时间

键的生存时间或过期时间 概述。 通过EXPIRE命令或者PEXIPIRE命令&#xff0c;客户端可以以秒或者毫秒精度为数据库中的某个键设置生存时间(Time To Live,TTL)&#xff0c;在经过指定的秒数或者毫秒数之后&#xff0c;服务器就会自动删除生存时间为0的键: 127.0.0.1:6379>…

Python零基础---爬虫技术相关

python 爬虫技术&#xff0c;关于数据相关的拆解&#xff1a; 1.对页面结构的拆解 2.数据包的分析&#xff08;是否加密了参数&#xff09;&#xff08;Md5 aes&#xff09;难易程度&#xff0c;价格 3.对接客户(433,334) # 数据库 CSV 4.结单&#xff08;发一部分数据&a…

酷开系统满足你的需求,加入酷开会员开启娱乐之旅

酷开科技深知家庭娱乐在我们生活中的重要性&#xff0c;因此&#xff0c;酷开科技不断努力为我们带来更好的内容和服务&#xff0c;在这里&#xff0c;我们能够享受到家庭娱乐的乐趣和便利&#xff0c;感受到酷开科技带来的温暖。电影迷、游戏迷还是音乐爱好者&#xff0c;酷开…

1236 - 二分查找

代码 #include<bits/stdc.h> using namespace std; int a[1100000]; int main() {int n,x,l,r,p,mid,i;cin>>n;for(i1;i<n;i)cin>>a[i];cin>>x;l1;rn;p-1;while(l<r){mid(rl)/2;if(a[mid]x){pmid;break;}else if(x<a[mid]) rmid-1;else if(x…

k8s为什么删除了pod但是还是没删除掉的问题,deployment在影响

deployment 影响pod删除 一、问题所在二、解决问题 一、问题所在 执行&#xff1a;kubectl get pods --all-namespaces&#xff0c;获取dashboard相关的pod kubectl get pods --all-namespaces | grep dashboardkubectl delete pod dashboard-metrics-scraper-546d6779cb-4x6…

备战秋招(coding篇)

其中coding题目来源于师兄面试经验 1、链表的结构体反转链表 本质上就是一个构造函数 struct ListNode{int val_;ListNode* next_;ListNode() : val_(0), next_(NULL) {}ListNode(int x) : val_(x), next_(NULL) {}ListNode(int x, ListNode* next) : val_(x), next_(next) …

【Spring Cloud】微服务通信概述

SueWakeup 个人主页&#xff1a;SueWakeup 系列专栏&#xff1a;学习技术栈 个性签名&#xff1a;人生乏味啊&#xff0c;我欲令之光怪陆离 本文封面由 凯楠&#x1f4f7; 友情赞助播出 目录 前言 1. Dubbo&#xff08;Spring Cloud Alibaba&#xff09;和 Spring Cloud 的适…

使用ollama + webui 运行任意大模型

安装ollama https://hub.docker.com/r/ollama/ollama docker run -d -v ~/Documents/work/softs/docker/ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama验证安装 # 进入容器docker exec -it ollama bash # 运行大模型 ollama run llama2 # 发送请求&…

【python + Django】Django模板语法 + 请求和响应

前言&#xff1a; 现在现在&#xff0c;我们要开始将变量的值展现在页面上面啦&#xff01; 要是只会显示静态页面&#xff0c;我们的页面也太难看和死板了&#xff0c; 并且数据库的数据也没法展现在页面上。 但是呢&#xff0c;模板语法学习之后就可以啦&#xff01;&…

笔记本8代i5和台式机12代i5的性能比较

一、 台式机12代i5 二、笔记本8代i5 在多核性能上差不多是2.4倍&#xff0c;所以跑大一点的Matlab或者别的程序&#xff0c;用台式机&#xff0c;后边实验室能用上超多核服务器另说。

【Flutter】文件选择器(file_picker)的用法

Flutter 没有提供内置的文件选择器&#xff0c;但社区内有人贡献了一个比较完整的解决方案——file_picker。 file_picker 的 API 简洁易用&#xff0c;支持全平台&#xff08;Android / iOS / Mac / Linux / Windows&#xff09;&#xff0c;是我开发桌面应用时的首选。 这边…

IDEA中快速配置Git

Git介绍&#xff1a; Git下载 idea中配置Git

蓝桥杯单片机快速开发笔记——串口通信

一、原理分析 二、思维导图 三、示例框架 #include <STC15F2K60S2.H> #include "HC573.h"void UartInit(void) //9600bps12.000MHz {SCON 0x50; //8位数据,可变波特率AUXR | 0x01; //串口1选择定时器2为波特率发生器AUXR & 0xFB; //定时器时钟12T模式…

流畅的 Python 第二版(GPT 重译)(六)

第三部分&#xff1a;类和协议 第十一章&#xff1a;一个 Python 风格的对象 使库或框架成为 Pythonic 是为了让 Python 程序员尽可能轻松和自然地学会如何执行任务。 Python 和 JavaScript 框架的创造者 Martijn Faassen。 由于 Python 数据模型&#xff0c;您定义的类型可以…

【Linux】进程通信

目录 一、管道通信 二、共享内存 三、消息队列 一、管道通信 管道是由操作系统维护的一个文件&#xff0c;管道通信的本质就是将管道文件作为临界资源&#xff0c;实现不同进程之间的数据读写&#xff0c;但是管道只允许父子进程或者兄弟进程之间的通信。 管道文件本身是全…

数据结构从入门到精通——堆排序

堆排序 前言一、堆排序的基本思想二、堆排序的特性总结三、堆排序的动图展示四、堆排序的代码实现向上建堆test.c 前言 堆排序是一种利用堆数据结构实现的排序算法。首先&#xff0c;它将待排序的数组构建成一个大顶堆或小顶堆。然后&#xff0c;通过不断将堆顶元素&#xff0…

MC10T1S-10BASE-T1S车载以太网转换器

10BASE-T1S车载以太网转换器 为10BASE-T1S车载以太网转换器&#xff0c;支持Multidrop bus line和Point-to-Point。采用的DB9接口类型&#xff0c;支持PLCA。10BASE-T1S是IEEE 802.3cg标准制定的IEEE汽车以太网的最新标准之一&#xff0c;采用UTP这样的一对无屏蔽的双芯电缆进行…

Uibot (RPA设计软件)财务会计Web应用自动化(批量开票机器人)

Uibot (RPA设计软件&#xff09;Mage AI智能识别&#xff08;发票识别&#xff09;———机器人的小项目友友们可以参考小北的课前材料五博客~ (本博客中会有部分课程ppt截屏,如有侵权请及请及时与小北我取得联系~&#xff09; 紧接着小北的前两篇博客&#xff0c;友友们我们…

webpack5零基础入门-13生产模式

1.生产模式介绍 生产模式是开发完成代码后&#xff0c;我们需要得到代码将来部署上线。 这个模式下我们主要对代码进行优化&#xff0c;让其运行性能更好。 优化主要从两个角度出发: 优化代码运行性能优化代码打包速度 2.生产模式准备 我们分别准备两个配置文件来放不同的…

【C++】为什么vector的地址与首元素地址不同?

文章目录 一、问题发现&#xff1a;二、结果分析三、问题解析 一、问题发现&#xff1a; &vector和&vector[0]得到的两个地址居然不相同&#xff0c;对数组array取变量名地址和取首元素地址的结果是相同的。这是为啥呢&#xff1f; 使用下面代码进行验证&#xff1a;…