iframe通信、跨标签通信的常见方案

前言

项目内嵌 iframe 也是一些大项目,或者久远项目会涉及到的问题,微前端可能遇到的稍微会多一些

此外,这个由于开发过程中并不是那么常用,很多人甚至过一段时间会忘记其通信方案,这里也记录一下与大家共享

同源情况通信

无论是iframe、跨标签页通信,只要是同源,那 iframe通信 基本都可以使用跨标签页通信,iframe 的一些方案却不能用在跨标签页

跨标签页通信(iframe通信亦可)

当然现在单页面SPA应用比较多,跨标签页很多场景都很少用了,了解一下,iframe用的相对就比较多了,并且跨标签页只能同源,否则无法正常手段通信(使用上websocket之类的当我没说😂)

使用 localStorage 通信

localStorage 是 HTML5 提供的一种在浏览器端存储数据的方式,数据存储在用户的浏览器中,同源情况下不同标签页、iframe可以访问相同的 localStorage 对象

浏览器提供了监听 localStorage 的变化事件,以实现标签页之间的通信。

在一个标签页中设置 localStorage 的值:

javascript 复制代码
localStorage.setItem('message', 'Hello from tab 1');

在另一个标签页中监听 localStorage 的变化事件:

javascript 复制代码
window.addEventListener('storage', function(event) {
  if (event.key === 'message') {
    console.log('Received message:', event.newValue);
  }
});

使用 Broadcast Channel API 通信

Broadcast Channel API 允许同源的不同浏览器上下文(如不同标签页、iframe 等)之间进行通信。

在一个标签页中创建 Broadcast Channel 对象并发送消息:

ini 复制代码
const bc = new BroadcastChannel('my_channel');
bc.postMessage('Hello from tab 1');

在另一个标签页中创建相同名称的 Broadcast Channel 对象并监听消息:

javascript 复制代码
const bc = new BroadcastChannel('my_channel');

bc.addEventListener('message', function(event) {
  console.log('Received message:', event.data);
});

可以创建一个 Broadcast Channel 对象,并通过它发送和接收消息。

使用 SharedWorker 通信

SharedWorker 是一种在浏览器后台运行的 Web Worker,可以被多个标签页共享。

标签页可以通过与 SharedWorker 进行通信来实现跨标签页的消息传递。

创建一个 SharedWorker 文件(例如 shared-worker.js):

ini 复制代码
const port = self.addEventListener('connect', function(event) {

  const workerPort = event.ports[0];
  workerPort.addEventListener('message', function(event) {
    // 处理接收到的消息
    workerPort.postMessage('Response from SharedWorker');
  });
  workerPort.start();
});

在标签页中连接 SharedWorker 并发送消息:

ini 复制代码
const sharedWorker = new SharedWorker('shared-worker.js');
const port = sharedWorker.port;
port.postMessage('Hello from tab 1');

port.addEventListener('message', function(event) {
  console.log('Received message:', event.data);
});

同源iframe通信

若 iframe 与父页面同源,可直接通过各自的window 对象相互访问(他们确实不是共用一个window哈,毕竟两个源,共用就很容易出乱子哈)

父页面通过 iframe 元素的 contentWindow 属性获取 iframe 的 window 对象,进而调用其方法或访问变量,这也是比较常见的 iframe 同源通信方案

js 复制代码
// 父页面代码 
const iframeWin = document.getElementById('myIframe').contentWindow; 

iframeWin.iframeMethod('消息内容'); // 调用 iframe 中的函数 

window.parentMethod = () => {
    我是父页面声明的函数
}

iframe 中通过 parenttop 属性获取父页面的 window 对象(top 指向最顶层页面,parent 指向直接父页面)

js 复制代码
// iframe
parent.parentMethod('消息内容'); // 调用父页面中的函数 

window.iframeMethod = () => {
    //我是iframe 中声明的函数
}

同源 iframe 与 iframe 之间通信

上面只讲了 父页面 与 iframe 之间的通信,没有讲 iframe 与 iframe 之间的通信呀

可以思考一下,实际上已经讲了,只不过,只差了一步思路而已

iframe 与 iframe 之间的通信 将父页面当做中间代理类进行交互即可,父类做一下中转即可

做一个例子,iframe1发起支付,由iframe2执行支付,并将支付结果传递给iframe1

js 复制代码
// 父页面代码 
const iframeWin1 = document.getElementById('myIframe').contentWindow; 
const iframeWin2 = document.getElementById('myIframe').contentWindow; 

iframeWin.iframeMethod('消息内容'); // 调用 iframe 中的函数 

window.sendPay = (message) => {
    //iframe2要调用的iframe1的声明的方法
    iframeWin1 && iframeWin1.iframe1Method && iframeWin1.iframe1Method(message)
}
window.payResult = (message) => {
     //iframe1要与iframe2通信,因此要调用iframe2的声明的方法
    iframeWin2 && iframeWin2.iframe1Method && iframeWin2.iframe1Method(message)
}

iframe1代码

js 复制代码
//iframe1
//收到iframe2传递过来的支付结果,也就是iframe2通过父页面通信调用iframe1的payResult方法
window.payResult = () => {
    //我是iframe1中声明的函数
}

parent.sendPay('消息内容'); // 通过父页面通知iframe2发起支付

iframe2代码

js 复制代码
iframe2
//发起支付,由外部也就是iframe1调用,实际是通过iframe1与父页面通信调用iframe2的sendPay方法
window.sendPay = (message) => {

}

parent.payResult(message) //将支付结果通过父页面通知到iframe1

是否看起来很麻烦,实际上不然,我们实际开发中两个模块都是独立的,如果直接使用手段,直接强行操控另一个iframe内容,那么结果将会很难维护(例如:直接获取父页面window方法,直接在当前frame随意获取到其他任何iframe的window、document,直接操控其他iframe,那么后续真的很难维护哈,不要开坏头😂)

实际这种子iframe之间互相交互的,可以另起一个类,比如叫:iframe1WithIframe2(实际可根据业务等起名都没问题,模块之间的交互功能放到一块,也方便维护)

同源其他诡异的通信方式(不推荐)

同源的时候,由于storage、indexDB 等缓存都可以直接访问到,因此有些人开始使用诡异手段了:

等待的一端直接轮训 storage、indexDB等,另外一段通信时更新 storage、indexDB等,更新后,会被轮训端查询到,因此实现的通信

虽然可以实现,但是不推荐哈,这种奇淫技巧属于没有什么其他手段应急的,正常有手段的时候不太推荐哈,其不算是一个正常的通信手段😂

iframe 跨域通信

若 iframe 与父页面不同源(跨域),需使用 postMessage API 进行安全通信

postMessage语法:

  • 发送方调用 window.postMessage(message, targetOrigin),接收方通过监听 message 事件获取消息。
  • message:需发送的数据(字符串、对象等,会被序列化)。
  • targetOrigin:指定接收方的域名(* 表示允许所有域名,但不安全,建议明确指定)。

父页面向 iframe 发送消息

js 复制代码
// 父页面代码 
const iframe = document.getElementById('myIframe'); 

iframe.contentWindow.postMessage('来自父页面的消息', 'https://iframe-domain.com'); // 明确目标域名

iframe 向父页面发送消息

js 复制代码
// iframe 内部代码 
window.parent.postMessage('来自 iframe 的消息', 'https://parent-domain.com'); // 明确父页面域名

ps:有人会觉得使用上面同源window交互方式不行么,可以自行尝试一下哈,非同源出于安全策略,浏览器不会让你拿到 iframe 的 window 信息的😂

最后

就介绍到这里吧,实际上这些也是常见方案,也就是比较简单易懂的通信方案,也是浏览器直接提供的

当有些通信这里都没办法做到的时候,可以尝试使用网络通信了,比如有些人非要跨越两个浏览器,那没辙,可上websocket、http了😂

相关推荐
崔庆才丨静觅5 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60616 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了6 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅6 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅6 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅7 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment7 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅7 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊7 小时前
jwt介绍
前端
爱敲代码的小鱼7 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax