Tab页间通信

一、场景

Tab 间通信存在不同的场景:

  • 同源网站下的 Tab 页间通信
  • 非同源网站下的 Tab 页间通信

二、同源网站下 Tab 页间的通信方式

按照通信的特征,分为三种方式点对点通信、广播通信、轮询通信

  • 点对点通信
    • window.postMessge
  • 广播通信
    • BroadCast Channel
    • Service Worker
    • LocalStorage
  • 轮询通信
    • IndexedDB

2.1 window.postMessge

当使用 window.open 打开一个新页面时,若两个 Tab 之间需要主动通信,则可以使用window.postMessage实现通信。

场景:在A页面使用window.open打开B页面,在B页面A页面发送消息。

特点:类似于点对点间的通信,其它的同源页面无法收到消息。

原理:

  • A 页面监听message事件
  • B 页面使用postMessage发送消息
  • B 页面可以获取 A 页面的 window 对象,一般使用 window.opener

具体实现(源码):

A 页面监听消息

/**
 * 事件映射
 */
const eventMap: PlainObject = {};

window.addEventListener('message', (ev) => {
  let { data } = ev;
  if (Object.prototype.toString.call(data) !== '[object Object]') return;

  let { key, args = [] } = data;
  let fn = eventMap[key];
  if (typeof fn === 'function') {
    if (!Array.isArray(args)) args = [args];
    fn(...args);
  }
});

/**
 * 注册Tab页事件
 *
 * @param key
 * @param fn
 */
export function registerTabEvent(key: string, fn: (...args: any[]) => void) {
  eventMap[key] = fn;
}

B 页面发送消息

type TMessage = { key: string; args?: any[] };
/**
 * 发送消息
 *
 * @param data
 * @returns
 */
export function sendTabMessage(data: TMessage) {
  let opener = window.opener;
  if (!opener) return;

  opener.postMessage(data, '/');
}

2.2 BroadCast Channel

BroadcastChannel 接口代理了一个命名频道,可以让指定 origin 下的任意 browsing context 来订阅它。它允许同源的不同浏览器窗口,Tab 页,frame 或者 iframe 下的不同文档之间相互通信。通过触发一个 message 事件,消息可以广播到所有监听了该频道的 BroadcastChannel 对象。

特点:

  • 广播通信

原理:

  • 页面创建BroadCast Channel实例
  • 为实例注册message事件

实现:

Demo

export default defineComponent({
  setup() {
    const instr = ref('');
    const outmsg = ref('');

    let bc = new BroadcastChannel('test');
    bc.onmessage = (ev) => {
      outmsg.value = ev.data;
    };

    const sendMsg = () => {
      bc.postMessage(instr.value);
    };

    return {
      instr,
      outmsg,
      sendMsg,
    };
  },
});

2.3 Service Worker

Service Worker 是一个运行在后台的 Worker,多页面间可以共享 Worker,使用 Worker 充当消息转发中心,实现多页面间的通信。

原理:

  • 多 Tab 共用同一份 Service Worker,每一个 Tab 是为 Client,通过 Service Worker 向每一客户端推送消息实现通信

实现:

Demo

ServiceWorker 注册message事件

// ServiceWorkerGlobalScope上下文中注册message事件
// 当监听到消息时,转发给每一个客户端
self.addEventListener('message', function (ev) {
  ev.waitUntil(
    self.clients.matchAll().then(function (clients) {
      if (!clients || clients.length === 0) {
        return;
      }

      // 向每一个客户端发送消息,包括自身
      clients.forEach(function (client) {
        client.postMessage(ev.data);
      });
    }),
  );
});

在客户端接收、发送消息

export default defineComponent({
  setup() {
    const instr = ref('');
    const outmsg = ref('');

    const sendMsg = () => {
      if ('serviceWorker' in navigator) {
        navigator.serviceWorker.controller?.postMessage(instr.value);
      }
    };

    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register('./tab-message.sw.js').then((data) => {
        console.log('Service Worker注册成功');
      });

      navigator.serviceWorker.addEventListener('message', (ev) => {
        outmsg.value = ev.data;
      });
    } else {
      console.log('浏览器不支持 serviceWorker');
    }

    return {
      instr,
      outmsg,
      sendMsg,
    };
  },
});

2.4 LocalStorage

localstorage 可以存储浏览器数据,同源时,共享数据。当同源下的两个 Tab 页需要监听对方数据变化时,使用 localstorage 是比较好的方式。

原理:

  • 两个 Tab 页同源
  • A 页面监听storage
  • B 页面使用setItem更新数据时,此时 A 页面可以监听到localstorage数据的变化

实现:

window.addEventListener('storage', function (e) {
  console.log(e.key, e.newValue);
});

2.5 IndexedDB

同源下的 Tab 可以访问相同的 IndexedDB,利用数据的全局存储特性,实现通信。

原理:

  • A 页面将数据存储到 IndexedDB 中
  • B 页面轮询查询 IndexedDB 中数据的变化

基于同样的原理,localstorage、sessionstorage 都可以采用这种方案

三、非同源页面间的通信

  • iframe

3.1 iframe

依靠 iframe 为媒介,可以实现非同源页面间的通信

热门文章

暂无图片
编程学习 ·

exe4j详细使用教程(附下载安装链接)

一、exe4j介绍 ​ exe4j是一个帮助你集成Java应用程序到Windows操作环境的java可执行文件生成工具,无论这些应用是用于服务器,还是图形用户界面(GUI)或命令行的应用程序。如果你想在任务管理器中及Windows XP分组的用户友好任务栏…
暂无图片
编程学习 ·

AUTOSAR从入门到精通100讲(126)-浅谈车载充电系统通信方案

01 引言 本文深入研究车载充电系统策略,设计出一套基于电动汽车电池管理系统与车载充电机的CAN通信协议,可供电动汽车设计人员参考借鉴。 02 电动汽车充电系统通讯网络 电动汽车整车控制系统中采用的是CAN总线通信方式,由一个整车内部高速CAN网络、内部低速CAN网络和一个充电…
暂无图片
编程学习 ·

CMake(九):生成器表达式

当运行CMake时,开发人员倾向于认为它是一个简单的步骤,需要读取项目的CMakeLists.txt文件,并生成相关的特定于生成器的项目文件集(例如Visual Studio解决方案和项目文件,Xcode项目,Unix Makefiles或Ninja输入文件)。然…
暂无图片
编程学习 ·

47.第十章 网络协议和管理配置 -- 网络配置(八)

4.3.3 route 命令 路由表管理命令 路由表主要构成: Destination: 目标网络ID,表示可以到达的目标网络ID,0.0.0.0/0 表示所有未知网络,又称为默认路由,优先级最低Genmask:目标网络对应的netmaskIface: 到达对应网络,应该从当前主机哪个网卡发送出来Gateway: 到达非直连的网络,…
暂无图片
编程学习 ·

元宇宙技术基础

请看图: 1、通过AR、VR等交互技术提升游戏的沉浸感 回顾游戏的发展历程,沉浸感的提升一直是技术突破的主要方向。从《愤怒的小鸟》到CSGO,游戏建模方式从2D到3D的提升使游戏中的物体呈现立体感。玩家在游戏中可以只有切换视角,进而提升沉浸…
暂无图片
编程学习 ·

flink的伪分布式搭建

一 flink的伪分布式搭建 1.1 执行架构图 1.Flink程序需要提交给 Job Client2.Job Client将作业提交给 Job Manager3.Job Manager负责协调资源分配和作业执行。 资源分配完成后,任务将提交给相应的 Task Manage。4.Task Manager启动一个线程以开始执行。Task Manage…
暂无图片
编程学习 ·

十进制正整数与二进制字符串的转换(C++)

Function one: //十进制数字转成二进制字符串 string Binary(int x) {string s "";while(x){if(x % 2 0) s 0 s;else s 1 s;x / 2;}return s; } Function two: //二进制字符串变为十进制数字 int Decimal(string s) {int num 0, …
暂无图片
编程学习 ·

[含lw+源码等]微信小程序校园辩论管理平台+后台管理系统[包运行成功]Java毕业设计计算机毕设

项目功能简介: 《微信小程序校园辩论管理平台后台管理系统》该项目含有源码、论文等资料、配套开发软件、软件安装教程、项目发布教程等 本系统包含微信小程序做的辩论管理前台和Java做的后台管理系统: 微信小程序——辩论管理前台涉及技术:WXML 和 WXS…
暂无图片
编程学习 ·

树莓派驱动DHT11温湿度传感器

1,直接使用python库 代码如下 import RPi.GPIO as GPIO import dht11 import time import datetimeGPIO.setwarnings(True) GPIO.setmode(GPIO.BCM)instance dht11.DHT11(pin14)try:while True:result instance.read()if result.is_valid():print(ok)print(&quo…
暂无图片
编程学习 ·

ELK简介

ELK简介 ELK是三个开源软件的缩写,Elasticsearch、Logstash、Kibana。它们都是开源软件。不过现在还新增了一个 Beats,它是一个轻量级的日志收集处理工具(Agent),Beats 占用资源少,适合于在各个服务器上搜集日志后传输给 Logstas…
暂无图片
编程学习 ·

Linux 基础

通常大数据框架都部署在 Linux 服务器上,所以需要具备一定的 Linux 知识。Linux 书籍当中比较著名的是 《鸟哥私房菜》系列,这个系列很全面也很经典。但如果你希望能够快速地入门,这里推荐《Linux 就该这么学》,其网站上有免费的电…
暂无图片
编程学习 ·

Windows2022 无线网卡装不上驱动

想来 Windows2022 和 windows10/11 的驱动应该差不多通用的,但是死活装不上呢? 搜一下,有人提到 “默认安装时‘无线LAN服务’是关闭的,如果需要开启,只需要在“添加角色和功能”中,选择开启“无线LAN服务…
暂无图片
编程学习 ·

【嵌入式面试宝典】版本控制工具Git常用命令总结

目录 创建仓库 查看信息 版本回退 版本检出 远程库 Git 创建仓库 git initgit add <file> 可反复多次使用&#xff0c;添加多个文件git commit -m <message> 查看信息 git status 仓库当前的状态git diff 差异对比git log 历史记录&#xff0c;提交日志--pret…
暂无图片
编程学习 ·

用Postman生成测试报告

newman newman是一款基于nodejs开发的可以运行postman脚本的工具&#xff0c;使用Newman&#xff0c;可以直接从命令运行和测试postman集合。 安装nodejs 下载地址&#xff1a;https://nodejs.org/en/download/ 选择自己系统相对应的版本内容进行下载&#xff0c;然后傻瓜式安…
暂无图片
编程学习 ·

Java面向对象之多态、向上转型和向下转型

文章目录前言一、多态二、引用类型之间的转换Ⅰ.向上转型Ⅱ.向下转型总结前言 今天继续Java面向对象的学习&#xff0c;学习面向对象的第三大特征&#xff1a;多态&#xff0c;了解多态的意义&#xff0c;以及两种引用类型之间的转换&#xff1a;向上转型、向下转型。  希望能…