前端跨页面通讯终极指南①:postMessage 用法全解析

前言

公司后台项目微前端是使用iframe方式,跨页面通讯postMessage就需要我们必须掌握。比如,弹窗页与父页面的数据同步、多个标签页间的状态共享、嵌入的iframe与宿主页面的交互等。

本文将从基础原理到实战场景,全面解析 postMessage 的用法,帮你轻松搞定各类跨页面通讯需求。

先看一张总结图,了解通讯的几种场景:

1. 什么是postMessage

postMessage 是用于在不同源的窗口、iframe、Worker之间安全地传递数据。打破了浏览器的"同源策略"限制,让跨源页面之间能够实现数据传递和事件通信。

postMessage 的使用逻辑非常简单,分为"发送数据"和"接收数据"两个步骤,本质是基于"消息发布-订阅"模式。

1.1 发送数据:targetWindow.postMessage()

发送数据的操作由"发送方窗口"调用 postMessage 方法完成,该方法挂载在窗口对象(window)上,语法如下:

ini 复制代码
targetWindow.postMessage(message, targetOrigin, [transfer]);

参数的含义和使用要点:

  1. targetWindow(必选) :接收消息的目标窗口对象,即"谁要接收这个消息"。常见的获取方式有: iframe的contentWindow:document.getElementById('iframeId').contentWindow(父页向子页发消息);
  2. window.opener:通过window.open()打开的新窗口,其内部通过opener获取父窗口(子页向父页发消息);
  3. window.parent:iframe内部通过parent获取父窗口(子页向父页发消息);
  4. message(必选) :要发送的数据,可以是字符串、数字、对象、数组等几乎所有类型。但需要注意: 数据会被隐式序列化为JSON格式传递,接收方需要自行解析(部分浏览器会自动反序列化,但建议显式处理以兼容);
  5. 避免发送过大的数据(如超过10MB),可能导致性能问题或传输失败。
  6. targetOrigin(必选) :目标窗口的"源"(协议+域名+端口),用于安全校验,即"只有该源的窗口才能接收消息"。取值规则: 具体源:如'https://www.example.com:8080',仅该源的窗口能接收;
  7. 通配符'*':允许所有源接收消息(极度危险,仅开发测试时临时使用);
  8. 空字符串'':仅适用于发送给file://协议的窗口(实际开发中极少用)。
  9. transfer(可选) :是一个包含可转移对象的数组,这些对象的所有权会从发送方转移到接收方,发送方后续无法再使用这些对象(如ArrayBuffer)。该参数使用场景较少,一般无需关注。

1.2 接收数据:监听 message 事件

接收数据的窗口需要监听自身的message事件,当有其他窗口通过postMessage发送消息时,该事件会被触发。语法如下:

javascript 复制代码
window.addEventListener('message', (event) => {
  // 处理接收的消息
}, false);

核心是解析事件对象event的三个关键属性:

  1. event.data :发送方传递的消息数据(即postMessage的第一个参数);
  2. event.origin:发送消息的窗口的"源"(协议+域名+端口),用于校验发送方身份;
  3. event.source:发送消息的窗口对象,可用于向发送方回传数据。

接收方必须通过event.origin校验发送方的合法性,避免接收恶意源发送的消息,这是与targetOrigin对应的双重安全保障。

2. 实战案例:同页面iframe通讯

父页面嵌入iframe,两者需要实现数据交互(如父页向子页传用户信息,子页向父页传操作结果)。

2.1 父->子

发送端(父页面):

js 复制代码
// 发送到指定 iframe
iframe1.contentWindow.postMessage({
    from: 'Parent (父页面)',
    message: '消息内容'
}, '*');

接收端(子页面):

js 复制代码
// 在 Vue 组件中监听消息
window.addEventListener('message', function(event) {
});

接收的数据:

2.2 子->父

发送端(子页面):

js 复制代码
// 从子页面发送消息到父页面
window.parent.postMessage({
    target: 'parent',
    from: 'Home (iframe1)',
    message: '消息内容'
}, '*');

接收端(父页面):

js 复制代码
// 父页面监听消息
window.addEventListener('message', function(event) {
    if (event.data.target === 'parent') {
        console.log('父页面处理消息:', event.data.message);
        // 在页面上显示日志
    }
});

父接收数据:

2.3 兄弟

对于兄弟页面,无法通过postMessage直接通讯,只能通过父页面进行中转,可以根据特定的类型,让父元素进行转发。具体不作介绍。

3. 实战案例:window.open打开方式通讯

通过window.open()打开新窗口后,父页可通过返回的窗口对象发送消息,子页通过window.opener获取父页窗口。

3.1 父->子

发送端(父页面):

js 复制代码
const child = window.open(url)
child.contentWindow.postMessage({
    from: 'Parent (父页面)',
    message: '消息内容'
}, '*');

接收端(子页面):

js 复制代码
window.addEventListener('message', function(event) {
});

3.2 子->父

发送端(子页面):

js 复制代码
// 从子页面发送消息到父页面
window.opener.postMessage({
    message: '消息内容'
}, '*');

接收端(父页面):

js 复制代码
// 父页面监听消息
window.addEventListener('message', function(event) {
});

3.3 兄弟

对于兄弟页面,无法通过句柄直接进行通讯,因为对于各自单独打开的页面,没法获取到窗口的句柄,也就没法进行消息的发送和监听。只能通过父页面进行中转,可以根据特定的类型,让父元素进行转发。具体不作介绍。

总结

最后总结一下:postMessage通过targetWindow.postMessage发送数据,其中targetWindow可以是iframe 的 contentWindow 属性或者执行window.open返回的窗口对象,通过监听message事件接收消息。

下一篇,我们将了解前端跨页面通讯的其他方案Broadcast Channel

如有错误,请指正O^O!

相关推荐
HIT_Weston几秒前
67、【Ubuntu】【Hugo】搭建私人博客(一)
前端·ubuntu·hugo
阿里巴啦12 分钟前
用React+Three.js 做 3D Web版搭建三维交互场景:模型的可视化摆放与轻量交互
前端·react·three.js·模型可视化·web三维·web三维交互场景
Liu.77423 分钟前
vue3组件之间传输数据
前端·javascript·vue.js
|晴 天|23 分钟前
前端闭包:从概念到实战,解锁JavaScript高级技能
开发语言·前端·javascript
开发者小天24 分钟前
react的拖拽组件库dnd-kit
前端·react.js·前端框架
用户44455436542634 分钟前
在Android开发中阅读源码的指导思路
前端
用户542778485154036 分钟前
ESM 模块(ECMAScript Module)详解
前端
全栈前端老曹1 小时前
【ReactNative】核心组件与 JSX 语法
前端·javascript·react native·react.js·跨平台·jsx·移动端开发
用户54277848515401 小时前
JavaScript 闭包详解:由浅入深掌握作用域与内存管理的艺术
前端
小小黑0071 小时前
快手小程序-实现插屏广告的功能
前端·javascript·小程序