如何优雅的实现 iframe 多层级嵌套通讯

前言

在前端开发项目中,不可避免的总会和 iframe 进行打交道,我们通常会使用 postMessage 实现消息通讯。

如果存在下面情况:

  • iframe 父子通讯
  • iframe 同层级通讯
  • iframe 嵌套层级通讯

当面对这种复杂的情况的时候,通讯不可避免成为复杂问题。

图片

快速开始

为了解决这复杂的问题,我开发了 iframe-bridge 来帮助大家优雅的解决这类问题。

npm install bridge-iframe
# pnpm
pnpm install bridge-iframe
# yarn
yarn add bridge-iframe

假设页面层级如下:

  • Main
    • Main/Node1

主页面(Main)

<h1>Main</h1>
<iframe src="Node1.html" id="Node1"></iframe>
import { IFrameBridge, IFrameMessage } from 'bridge-iframe';

// 创建桥接对象
const bridge = new IFrameBridge;
// 连接直接下属节点 Node1 关联 iframe 窗口
birdge.ifrme('Node1', document.getElementById('Node1'));

// 提供给其他 iframe 节点调用的方法(可以定义无数个)
birdge.on('say', async (vo: IFrameMessage) => {
	vo.getData(); // 获取请求数据
	vo.getResult(); // 获取响应数据
	return '来自于 Main';
});

// 等待桥接初始化完成
birdge.ready(async () => {
	console.log('Main 初始化完成!!!');
});

// 等待 Node1 节点桥接完成
birdge.ready('Node1', async () => {
	console.log('Watch Node1 初始化完成!!!');

	// 请求 Node1 的 say 方法
	birdge.request({
		name: 'Node1',
		method: 'say',
	}).then((vo: any) => {
		console.log('在 Main 中请求 Node1.say 方法', vo);
	}).catch((err: any) => {
		console.log('出现错误', err);
	});
});

// 窗口销毁时
bridge.destroy();

子页面(Node1)

<h1>Node1</h1>
import { IFrameBridge } from 'bridge-iframe';

// 创建桥接对象
const bridge = new IFrameBridge({ name: 'Node1' });

// 提供给其他 iframe 节点调用的方法(可以定义无数个)
birdge.on('say', async (vo: IFrameMessage) => {
	return '来自于 Nodeq';
});

// 等待桥接初始化完成
birdge.ready(async () => {
	console.log('Node1 初始化完成!!!');
});

// 等待 Node1 节点桥接完成
birdge.ready('Main', async () => {
	console.log('Watch Main 初始化完成!!!');

	// 请求 Main 的 say 方法
	birdge.request({
		name: 'Main',
		method: 'say',
	}).then((vo: any) => {
		console.log('在 Node1 中请求 Main.say 方法', vo);
	}).catch((err: any) => {
		console.log('出现错误', err);
	});
});

// 窗口销毁时
bridge.destroy();

其中关于请求 name 在这里称呼为 iframe node域名 作为通讯标识。
关于子节点的名称可以为任意名称,但有两类名称是内置的代表特殊作用不能被使用。

  • Main 作为 主节点/主窗口 的名称地址
  • Parent 作为只请求上一级节点的名称标识,不管上层节点名字是什么

假设页面层级如下(更复杂):

  • Main

    • Main/Node1
      • Main/Node1/Node1-1
      • Main/Node1/Node1-2
    • Main/Node2
      • Main/Node2/Node2-1
      • Main/Node2/Node2-2
  • 在这里还是一样的,创建主页面桥接对象,并关联子页面 iframe 相对的子页面也创建有名称的桥接对象。

  • 还是通过注册一些可以被其他节点调用的方法来实现双通讯的。

实现原理

这里参考了计算机网络的 交换机 的模式来实现跨层级转发。

网络模型

                         /——> (子节点1)
(父节点) <———> (节点) <——————> (子节点2)
                         \——> (子节点n) ...
  • 每个 节点 都有 上级节点x1下级节点xN 的结构。
  • 消息通讯的核心本质还是 postMessage 来实现。
  • 当消息经过 节点 的时候,通过 message.path 判断 message 是向上 window.parent.postMessage() 传递还是向下 iframe.contentWindow.postMessage() 传递。
  • 当消息经过 节点 的时候,会记录经过的路径为 tracks{ 节点名称, 转发方向 }[] 以此来实现初始地址分配,以及消息返回路径确认。

系统协议

为了实现跨层级通讯,动态为 节点 分配地址,得实现 节点名称映射地址库 来实现。

  • 主窗口/页面提供如下内置方法:
    • @bridge/online 通知主窗口注册地址
    • @bridge/domain 获取名称映射地址
    • @bridge/mapping 获取所有映射地址
  • 所有窗口/页面提供如下内置方法:
    • @bridge/ready 节点准备好了吗?

为了方便调用,定义了如下内置地址:

  • Main 请求主窗口地址
  • Parent 向上级请求窗口(无论层级高低都向上级请求)

通讯模拟:

页面层级

  • Main
    • Main/Node1
      • Main/Node1/Node1-1
      • Main/Node1/Node1-2
    • Main/Node2
      • Main/Node2/Node2-1
      • Main/Node2/Node2-2

向上请求 Main/Node1/Node1-1Main

  • <内置协议获取地址>
  • Main/Node1/Node1-1 请求 ↑↑↑Main/Node1
    • tracks[{Node1-1:U}]
  • Main/Node1 转发 ↑↑↑Main
    • tracks[{Node1-1:U}, {Node1:U}]
  • Main 处理逻辑
  • Main 响应 ↓↓↓Main/Node1
    • tracks[{Node1-1:U}]
  • Main/Node1 转发 ↓↓↓Main/Node1/Node1-1
    • tracks[]
  • Main/Node1/Node1-1 收到响应

向下请求 MainMain/Node1/Node1-1

  • <内置协议获取地址>
  • Main 请求 ↓↓↓Main/Node1
    • tracks[{Main:D}]
  • Main/Node1 转发 ↓↓↓Main/Node1/Node1-1
    • tracks[{Main:D}, {Node1:D}]
  • Main/Node1/Node1-1 处理逻辑
  • Main/Node1/Node1-1 响应 ↑↑↑Main/Node1
    • tracks[{Main:D}]
  • Main/Node1 转发 ↑↑↑Main
    • tracks[]
  • Main 收到响应

同级请求 Main/Node1/Node1-1Main/Node1/Node1-2

  • <内置协议获取地址>
  • Main/Node1/Node1-1 请求 ↑↑↑Main/Node1
    • tracks[{Node1-1:U}]
  • Main/Node1 转发 ↓↓↓Main/Node1/Node1-2
    • tracks[{Node1-1:U}, {Node1:D}]]
  • Main/Node1/Node1-2 处理逻辑
  • Main/Node1/Node1-2 响应 ↑↑↑Main/Node1
    • tracks[{Node1-1:U}]
  • Main/Node1 转发 ↓↓↓Main/Node1/Node1-1
    • tracks[]
  • Main/Node1/Node1-1 收到响应

跨级请求 Main/Node1/Node1-1Main/Node2/Node2-1

  • <内置协议获取地址>
  • Main/Node1/Node1-1 请求 ↑↑↑Main/Node1
    • tracks[{Node1-1:U}]
  • Main/Node1 转发 ↑↑↑Main
    • tracks[{Node1-1:U}, {Node1:U}]
  • Main 转发 ↓↓↓Main/Node2
    • tracks[{Node1-1:U}, {Node1:U}, {Main:D}]
  • Main/Node2 转发 ↓↓↓Main/Node2/Node2-1
    • tracks[{Node1-1:U}, {Node1:U}, {Main:D}, {Node2:D}]
  • Main/Node2/Node2-1 处理逻辑
  • Main/Node2/Node2-1 响应 ↑↑↑Main/Node2
    • tracks[{Node1-1:U}, {Node1:U}, {Main:D}]
  • Main/Node2 转发 ↑↑↑Main
    • tracks[{Node1-1:U}, {Node1:U}]
  • Main 转发 ↓↓↓Main/Node1
    • tracks[{Node1-1:U}]
  • Main/Node1 转发 ↓↓↓Main/Node1/Node1-1
    • tracks[]
  • Main/Node1/Node1-1 收到响应

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

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

相关文章

uniapp制作安卓原生插件踩坑

1.uniapp和Android工程互相引用讲解 uniapp原生Android插件开发入门教程 &#xff08;最新版&#xff09;_uniapp android 插件开发-CSDN博客 2.uniapp引用原生aar目录结构 详细尝试步骤1完成后生成的aar使用&#xff0c;需要新建nativeplugins然后丢进去 3.package.json示例…

机器学习——过拟合

一、过拟合得表现 模型在训练过程中&#xff0c;除了会出现过拟合现象&#xff0c;还有可能出现欠拟合的情况。相比而言&#xff0c;后者通常发生在建模前期&#xff0c;只要做好特征工程一般可以解决模型欠拟合问题。下图描述了模型在训练数据集上的三种情况&#xff1a; 其…

二阶响应曲面分析

文章目录 一、二阶响应曲面介绍1.1 什么时候用二阶响应曲面1. 非线性关系2. 探寻极值&#xff08;最大化或最小化&#xff09;3. 复杂的交互作用4. 精度要求高5. 探索性分析阶段 1.2响应曲面的特征 二、实例说明2.1 二阶模型求解 参考自《实验设计与数据处理》一书 一、二阶响应…

HTML5 服务器发送事件(Server-Sent Events)

参考&#xff1a;HTML5 服务器发送事件(Server-Sent Events) | 菜鸟教程 一&#xff0c;sse介绍 Server-Sent 事件 - 单向消息传递 Server-Sent 事件指的是网页自动获取来自服务器的更新。 以前也可能做到这一点&#xff0c;前提是网页不得不询问是否有可用的更新。通过服务…

Verilog基础语法——parameter、localparam与`define

Verilog基础语法——parameter、localparam与define 写在前面一、localparam二、parameter三、define写在最后 写在前面 在使用Verilog编写RTL代码时&#xff0c;如果需要定义一个常量&#xff0c;可以使用define、parameter和localparam三种进行定义与赋值。 一、localparam …

【Linux深造日志】运维工程师必会Linux常见命令以及周边知识!

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引入 哈喽各位宝子们好啊&#xff01;我是博主鸽芷咕。日志这个东西我相信大家都不陌生&#xff0c;在 linxu/Windows 系统…

新媒体运营-----短视频运营-----PR视频剪辑----字幕

新媒体运营-----短视频运营-----PR视频剪辑-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/138079659 文章目录 1. PR创建字幕2. 通过剪映来智能添加字幕3. 如何像文本对象一样&#xff0c;给字幕做特效4. 写字特效 1. PR创建字…

ssm079基于SSM框架云趣科技客户管理系统+jsp

客户管理系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本客户管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处…

Gateway基础知识

文章目录 Spring Cloud GateWay 用法核心概念请求流程两种配置方式设置日志&#xff08;建议设置&#xff09;路由的各种断言断言The After Route Predicate FactoryThe Before Route Predicate FactoryThe Between Route Predicate FactoryThe Cookie Route Predicate Factory…

Java使用IText根据pdf模板创建pdf文件

1.导包 <dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.10</version></dependency><dependency><groupId>com.itextpdf</groupId><artifactId>itext-as…

Rust之构建命令行程序(六):信息写入

开发环境 Windows 11Rust 1.77.2 VS Code 1.88.1 项目工程 这次创建了新的工程minigrep. 将错误信息写入标准错误而不是标准输出 此时&#xff0c;我们正在使用宏println!将所有输出写入终端。在大多数终端中&#xff0c;有两种输出:一般信息的标准输出&#xff08;stdout&…

docker安装【zookeeper】【kafka】【provectuslabs/kafka-ui】记录

目录 1.安装zookeeper:3.9.2-jre-172.安装kafka:3.7.03.安装provectuslabs/kafka-ui &#xff08;选做&#xff09;新环境没有jdk&#xff0c;安装jdk-17.0.10备用 mkdir -p /export/{data,apps,logs,conf,downloads}cd /export/downloadscurl -OLk https://download.oracle.…

【VScode】VScode+如何从git上面拉取代码?

目录标题 1、打开VSCode。File>New Window。2、打开集成终端&#xff08;Terminal > New Terminal 或使用快捷键Ctrl \)。3、在终端中&#xff0c;使用Git命令克隆仓库。4、打开项目。 1、打开VSCode。File>New Window。 2、打开集成终端&#xff08;Terminal > …

基于HAL库的stm32中定时器的使用--定时器中断每隔一秒进行led灯的闪烁以及定时器生成PWM

一&#xff1a;什么是定时器 &#xff08;1&#xff09;stm32定时器&#xff0c;是存在于stm32单片机中的一个外设。stm32共有八个定时器&#xff0c;两个高级定时器&#xff08;TIM1、TIM8&#xff09;&#xff0c;四个通用定时器&#xff08;TIM2、TIM3、TIM4、TIM5&#xff…

Java中的ArrayList集合

特点&#xff1a; ArrayList中的一些方法&#xff1a; 1、add(Object element):向集合的末尾添加元素 add(int index,Object element):在列表的指定位置&#xff08;从0开始&#xff09;插入指定元素 2、size():返回列表的中的元素个数 3、get(int index):返回下标为index位置的…

基于昇腾AI 使用AscendCL实现垃圾分类和视频物体分类应用

现如今&#xff0c;人工智能迅猛发展&#xff0c;AI赋能产业发展的速度正在加快&#xff0c;“AI”的需求蜂拥而来&#xff0c;但AI应用快速落地的过程中仍存在很大的挑战&#xff1a;向下需要适配的硬件&#xff0c;向上需要完善的技术支持&#xff0c;两者缺一不可。 基于此&…

SQL中的锁

一、概述 介绍 锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中&#xff0c;除传统的计算资(CPU、RAM、I/0)的争用以外&#xff0c;数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题&#xff0c;锁冲…

02-JVM学习记录-运行时数据区

二、运行时数据区 每个JVM只有一个Runtime实例&#xff0c;只有一个运行时数据区。 虚拟机栈、堆、方法区最重要 方法区和堆与虚拟机的生命周期相同&#xff08;随虚拟机启动而创建&#xff0c;虚拟机退出而销毁&#xff09;&#xff0c;程序计数器、虚拟机栈、本地方法栈生命…

JavaScript云LIS系统概述 前端框架JQuery+EasyUI+Bootstrap医院云HIS系统源码 开箱即用

云LIS系统概述JavaScript前端框架JQueryEasyUIBootstrap医院云HIS系统源码 开箱即用 云LIS&#xff08;云实验室信息管理系统&#xff09;是一种结合了计算机网络化信息系统的技术&#xff0c;它无缝嵌入到云HIS&#xff08;医院信息系统&#xff09;中&#xff0c;用于连…

wps/word中字体安装教程

问题&#xff1a;下载的字体怎么导入wps/word wps或word中没有相应字体&#xff0c;怎么导入。其实方法很简单。 Step 1&#xff1a;下载字体 首先&#xff0c;在网上搜索自己喜欢的字体&#xff0c;然后下载到本地。字体的格式通常是.ttf 下面是我网上找的字体&#xff08…