写在前面
假设有这样一个场景,你接到一个项目,需要在这个项目上完成一次迭代,但是你发现这个项目已经是 10 年前的老项目了。框架、组件库都非常老。。。。你无从下手,不知所措,如果这时去阅读项目老代码并在这个基础上进行开发,无疑是非常崩溃的,而且效率非常低下。
众所周知,现在的网页开发都是用的最新的框架,例如 Vue、React 开发起来都非常顺手,而且节约时间,这个时候你就在想,有没有可能自己用新框架开发,然后再在老项目上去使用,这样是不是就快很多了,这时你又重燃希望了,又可以开心的写代码了。
但这个时候又有一个新问题,就是如何把自己的新框架嵌入到老框架里面呢,这个简单,只需要把打包的js、css 资源引入到老框架不就行了。
于是你感觉问题就这么简单的解决了,但是你又发现了一个新问题,就是如何让两者可以实现通信, 新框架的资源只是引入进去了,但是两者并没有产生实际的交互之间的关系。
这时你又陷入了沉思,于是经过一番调研你发现了一个好东西,window.postMessage 可以实现这个需求!
上面说了这么多废话其实就是为了更清晰的描述这个需求,那么接下来就进入正题,一起来看看到底该如何利用 postmessage 实现这个需求吧!
什么是 postMessage
window.postMessage()方法提供了一种安全的跨域通信机制。在浏览器的安全策略中,不同源(协议、域名、端口不同)的页面之间通常是限制相互访问的。但是通过window.postMessage(),一个窗口(可以是一个iframe、一个新打开的窗口等)可以向另一个窗口发送消息,只要目标窗口正确地设置了消息接收的事件监听器。
说白了 postMessage 的主要作用是实现不同窗口(包括跨域的iframe、新打开的窗口等)之间安全地发送和接收消息,从而进行跨窗口通信。
基本语法
发送方
js
window.postMessage(message, targetOrigin);
接收方
js
window.addEventListener('message', function (event) {
var messageData = JSON.parse(event.data);
console.log(messageData.key);
});
演示一下
上面我们已经介绍了怎么使用,接下来我们就实战一下怎么使用。
老框架中
老框架中我们使用 jquery,在 jquery 中使用 react 框架。
我们现在老框架中进行发送通信,然后在新框架中接收通信即可。
下面这块代码很简单,我们给按钮绑定点击事件,点击的时候发送 postmessage 通信。
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>jQuery to React Modal Communication</title>
</head>
<body>
<button id="openModal">Open React Modal</button>
<!-- 挂载新框架 -->
<div id="root"></div>
<!-- jquery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- 新框架js资源 -->
<script src="build/static/js/main.eb6f11e8.js"></script>
<!-- 新框架css资源 -->
<link rel="stylesheet" href="build/static/css/main.8da51b4f.css" />
<script>
$(document).ready(function () {
$('#openModal').on('click', function () {
// 通过 postMessage 触发 React modal 显示
const data = {
userId: 123,
username: 'johndoe',
}
window.postMessage({ type: 'openModal', data }, '*')
})
})
</script>
</body>
</html>
发送通信已经搞定了,但是我们需要在老框架中引入新项目的资源,也打包后的就是 css、js 资源。
js
<script src="build/static/js/main.eb6f11e8.js"></script
<link rel="stylesheet" href="build/static/css/main.8da51b4f.css" />

因为新框架需要有一个 root 节点挂载元素,我们将 root 节点也一并引入。
js
<div id="root"></div>
新框架
老框架的工作已经做好了,新框架其实就是需要在页面中接受 postmessage 事件即可。
我们在 useEffect 中监听 postmessage 事件,并且在规定 type 为 openModal 时设置相应的数据,非常简单的一段代码,主要还是为了解释 postmessage 的用法。
js
import React, { useEffect, useState } from 'react'
import './Modal.css'
const Modal = () => {
const [data, setData] = useState(null)
const [isVisible, setIsVisible] = useState(false)
useEffect(() => {
const handleMessage = (event) => {
if (event.data.type === 'openModal') {
console.log('event', event)
setData(event.data.data) // 设置数据
setIsVisible(true)
}
}
window.addEventListener('message', handleMessage)
return () => window.removeEventListener('message', handleMessage)
}, [])
const handleClose = () => {
setIsVisible(false)
setData(null)
}
return isVisible ? (
<div className="modal">
<div className="modal-content">
<h2>React Modal1111</h2>
<p>User ID: {data?.userId}</p>
<p>Username: {data?.username}</p>
<button onClick={handleClose}>Close Modal</button>
</div>
</div>
) : null
}
export default Modal
效果
好了准备工作都好了,现在来看一下效果
首先运行老代码,然后点击按钮,我们先要的效果时打开一个弹窗,并且把老项目的数据带过来并且展示在弹窗上面。

自己动手试试
现在还留了一个小的作业,就是点击 close modal 的时候,需要新框架向老框架发送通信,通知老框架,关闭了弹窗,然后弹出一个弹窗,大家感兴趣可以自己试试哈,如下:
