普通视图

发现新文章,点击刷新页面。
今天 — 2025年11月26日首页

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

2025年11月25日 17:01

前言

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

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

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

image.png

1. 什么是postMessage

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

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

1.1 发送数据:targetWindow.postMessage()

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

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发送消息时,该事件会被触发。语法如下:

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

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

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

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

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

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

2.1 父->子

发送端(父页面):

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

接收端(子页面):

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

接收的数据:

image.png

2.2 子->父

发送端(子页面):

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

接收端(父页面):

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

父接收数据:

image.png

2.3 兄弟

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

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

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

3.1 父->子

发送端(父页面):

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

接收端(子页面):

window.addEventListener('message', function(event) {
});

3.2 子->父

发送端(子页面):

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

接收端(父页面):

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

3.3 兄弟

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

总结

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

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

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

❌
❌