如何优雅的实现 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.mzph.cn/pingmian/4646.shtml

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

相关文章

Unity 物体触碰事件监听

声明委托 public delegate void MyDelegate(Collider trigger); C# 委托&#xff08;Delegate&#xff09; | 菜鸟教程 (runoob.com)https://www.runoob.com/csharp/csharp-delegate.html 定义委托 public MyDelegate onTriggerEnter; public MyDelegateonTriggerStay; pub…

用来传输文件的协议-FTP

一.FTP协议--文件传输协议 1.了解FTP协议 &#xff08;1&#xff09;FTP服务是用来传输文件的协议 FTP&#xff08;File Transfer Protocol&#xff0c;文件传输协议&#xff09;是TCP/IP协议组中的协议之一&#xff0c;用于互联网上的控制文件的双向传输。是传输文件到Linu…

《Fundamentals of Power Electronics》——全桥型隔离降压转换器

以下是关于全桥型隔离降压转换器的相关知识点&#xff1a; 全桥变压器隔离型降压转换器如下图所示。 上图展示了一个具有二次侧绕组中心抽头的版本&#xff0c;该电路常用于产生低输出电压。二次侧绕组的上下两个绕组可以看作是两个单独的绕组&#xff0c;因此可以看成是具有变…

Internal server error: [less] Unrecognised input

我之前查了资料&#xff0c;网上有的人说是 less 的配置不正确&#xff08;这种问题引起的可以查找其他博客看&#xff09;&#xff0c;但是后面经过我慢慢的查找&#xff0c;还有一种可能&#xff0c;就是 less 的写法不对&#xff0c;下面我来解释一下我的错误和处理过程 在…

kaggle无法注册怎么办

在浏览kaggle网站&#xff0c;或者是参加kaggle竞赛时&#xff0c;常常会遇到需要登陆kaggle账号的情况。而在注册时&#xff0c;却发现无论如何也无法弹出人机识别的验证码&#xff0c;导致无法注册成功。本文会手把手的讲解一种注册kaggle的方法&#xff08;edge浏览器&#…

安装依赖报错前端安装某个依赖安装不上可能是node版本过高 升级或者降低node版本方式

安装依赖报错安装某个依赖安装不上可能是node版本过高 升级或者降低node版本方式 安装某个依赖安装不上 或者node版本过高 升级或者降低node版本 收藏关注一下吧 开发中难免总会需要切换node版本 需要的时候在找麻烦 主页 中还有更多干货分享

分享开放原子AtomGit开源协作平台评测报告

AtomGit平台的总体介绍 开放原子开源基金会是致力于推动全球开源事业发展的非营利机构&#xff0c;于 2020 年 6 月在北京成立&#xff0c;由阿里巴巴、百度、华为、浪潮、360、腾讯、招商银行等多家龙头科技企业联合发起。目前有三个主要机构设置&#xff0c;技术监督委员会&…

You need know something from Xcode 9

xcode 9 一些快捷的功能使用介绍 首先是弹框 目前发现弹框中的提取方法等功能存在一些问题&#xff0c;期待后续的版本能解决这些问题&#xff0c;弹框里面主要包含跳转变量或者方法的跳转、快捷帮助、折叠方法、重命名方法名称、提取方法等功能 笔者觉得rename功能比较好用&…

【新手入门】Git的使用方法,上传自己的项目到GitHub上

Git新手教程 一、Git下载安装二、初始化设置1.网端设置2.用户设置 三、开始上传自己项目1.创建新文件夹&#xff0c;克隆项目地址2.上传文件3.成功运行并上传的界面 报错1.fatal: unable to access https://github.com/ssrzero123/STF-YOLO.git/: error setting certificate fi…

NDK 编译(二)—— NDK 编译与集成 FFmpeg

NDK 编译系列文章共三篇&#xff0c;目录如下&#xff1a; NDK 编译&#xff08;一&#xff09;—— Linux 知识汇总 NDK 编译&#xff08;二&#xff09;—— NDK 编译与集成 FFmpeg NDK 编译&#xff08;三&#xff09;—— CMake 原生构建工具 在使用 NDK 进行音视频开发时&…

icloud里面的通讯录怎么全部导出,通讯录格式如何转换,简单!

随着科技的发展&#xff0c;我们的日常生活越来越离不开手机和各种应用程序。通讯录作为手机中最重要的功能之一&#xff0c;记录着我们的亲朋好友、同事和业务伙伴的联系方式。因此&#xff0c;定期备份通讯录变得尤为重要。iCloud作为苹果公司提供的一项云服务&#xff0c;可…

【触摸案例-控件不能响应的情况 Objective-C语言】

一、接下来,我们来说这个“控件不能响应的情况”, 1.素材里边,有一个“不接受用户交互的情况”,这么一个代码,把它打开, 把这个项目啊,复制过来,改一个名字,叫做“04-控件不能响应的情况”, 打开之后,command + R,运行一下, 在storyboard上,你也可以看得出来,我…

java-stream流案例

需求 代码 Vote类 // 1. 定义一个投票类 public class Vote {private String name;private ArrayList<String> voteList;public Vote(String name, ArrayList<String> voteList) {this.name name;this.voteList voteList;}public String getName() {return nam…

16册 | 移动机器人(自动驾驶)系列

此文档整理推荐了16本移动机器人&#xff08;自动驾驶&#xff09;相关的书籍&#xff0c;内容包括&#xff1a;ROS、机器人基础开发、分布式机器人控制、集群机器人控制、嵌入式机器人、多传感器融合等等。 学习&#xff0c;切勿急于求成&#xff0c;读书自学&#xff0c;需多…

就业班 第三阶段(tomcat) 2401--4.28 day1 tomcat1安装配置及单机多实例

企业 Tomcat 运维 文章目录 企业 Tomcat 运维一、Tomcat 简介1、Tomcat好帮手---JDK2、安装Tomcat & JDK1、系统环境说明2 、安装JDK3、安装Tomcat 二、Tomcat目录介绍1、tomcat主目录介绍2、webapps目录介绍3、Tomcat配置介绍&#xff08;conf&#xff09;4、Tomcat的管理…

Qt窗口

QMainWindow Qt 窗⼝ 是通过 QMainWindow类 来实现的。 QMainWindow 是⼀个为⽤⼾提供主窗⼝程序的类&#xff0c;继承⾃ QWidget 类&#xff0c;并且提供了⼀个预定义的 布局。QMainWindow 包含 ⼀个菜单栏&#xff08;menu bar&#xff09;、多个⼯具栏(tool bars)、多个浮动…

JavaScript底层原理(栈、堆、主线程、任务队列、事件循环机制)

1. 栈(heap)和堆(stack) 栈是栈内存的简称&#xff0c;堆是堆内存的简称。顾名思义&#xff0c;内存是干啥的&#xff1f;内存就是用来存放数据的。 栈 栈只有一个入口&#xff0c;同时也是出口&#xff0c;数据遵循先进后出、后进先出的原则。 栈用于存放基本类型数据和引用…

安装库后JupyterLab一直报ModuleNotFoundError问题解决

背景&#xff1a; 先安装的Python3.10&#xff0c;安装在默认路径&#xff1a; C:\Users\#用户名省略#\AppData\Local\Programs\Python\Python310\ 后安装的Anaconda&#xff0c;更改过路径在D盘&#xff1a; D:\ProgramData\anaconda3 此时C盘Python安装路径下Scripts文件…

YAW-100B全自动压力试验机

一、简介 微机控制压力试验机测控系统采用高精度数字伺服阀&#xff0c;具有力闭环控制功能&#xff0c;能够实现等载荷速率加载或等应力速率加载&#xff0c;控制精度高&#xff0c;可靠性好&#xff0c;完全满足GB/T 17617《水泥胶沙强度检验方法&#xff08;ISO方法&#x…

matlab学习004-使用matlab绘制卷积波形图

目录 1&#xff0c;序列&#xff1a;x(n)u(n-2)-u(n-10)&#xff0c;h(n)((0.9)^n)*u(n) 1&#xff09;前期基础 ①conv函数 ②离散单位阶跃信号 2&#xff09;波形图 3&#xff09;代码 ①使用input方法 ②代码改进【推荐使用】 2&#xff0c;信号x(t)2[u(t1)-u(t…