是一款基于 postMessage 来处理父子页面通信的库,轻量且好用。一个强大的、简单的、基于 promise 的 postMessage iFrame 通信库。
postmate 官方地址
https://github.com/dollarshaveclub/postmate
基于 promise 的 API,用于优雅和简单的通信。
安全的双向父 <-> 子握手,并带有消息验证。
子代暴露一个可检索的模型对象,父代可以访问。
子代发出事件,父代可以监听。
父代可以调用子代的函数。
零依赖性。如果需要的话,可以为 Promise API 提供自己的 polyfill 或抽象。
轻量级,大小约为 1.6kb(缩小和压缩后)。
//yarn
$ yarn add postmate
//npm
$ npm i postmate --save
这里提供一个 demo 内含 React 和 Vue 两个项目,其中 React 项目为父项目,Vue 项目为子项目,启动后,父项目会通过 iframe 方式自动加载子项目。
#父项目react
cd react
yarn
yarn start
#子项目vue-demo
cd vue-demo
yarn
yarn serve
3、项目运行时截图和视频
截图一:

截图二:
完整流程如下:

4、重要代码详解,父项目 react
import { useEffect, useRef, useState } from "react";
import yayJpg from "../assets/yay.jpg";import PostMate from "postmate";
import type { ParentAPI, PostmateOptions } from "postmate";import "./index.less";function HomePage() {const childRef = useRef(null);const [loading, setLoading] = useState(false);// 初始化const init = (params: PostmateOptions) => {console.log("++++++++++parent++++++++: 初始化parent页面postmate实例");const handshake = new PostMate({ ...params });// 回调handshake.then((child) => {console.log("++++++++++parent++++++++: 接收到child页面握手成功后,回传消息");// 存储child 到 childRef中childRef.current = child;child.on("some-event", (data) => {console.log(data);initChildParams();});// 更新UIupdateStyle(child);}).catch((error) => {console.log(error);});};useEffect(() => {init({container: document.getElementById("iframe-container"),url: "http://localhost:8080/",name: "my-iframe-name",classListArray: ["my-class"],});return () => {// 销毁iframechildRef.current.destroy();};}, []);// 更新UIconst updateStyle = (child: ParentAPI) => {// 采用轮训方式获取child页面高度setInterval(() => {child.get("height").then((height) => {child.frame.style.height = `${height + 80}px`;});}, 100);};// 设置child页面参数const initChildParams = () => {console.log("++++++++++parent++++++++: 调用child页面中defaultValues方法,设置表单默认参数");childRef.current.call("defaultValues",JSON.stringify({userErp: "yangyujiao5", //当前用户的erp,表单需要bamboolUrl: "bamboolUrl", //测试包链接sdkName: "sdkName", //SDK名称sdkVersion: "sdkVersion", //SDK版本}));};// 触发child页面的提交函数const onChildSubmitChange = (params: Record) => {return new Promise((resolve, reject) => {console.log("++++++++++parent++++++++: 调用child页面中onSubmit方法,触发child表单提交");// 触发child页面的onChildSubmit方法childRef.current.call("onSubmit", { ...params });// 在parent页面注册事件,用来获取child页面submit-callback方法childRef.current.on("submit-callback", (data: any) => {console.log("++++++++++parent++++++++: 接收到child页面表单提交成功后通知");if (data?.code === 200) {resolve(data);} else {reject();}});});};// parent提交函数const onSubmit = async () => {console.log("++++++++++parent++++++++: 触发parent页面表单提交方法");try {setLoading(true);const { code, sdkID } = await onChildSubmitChange({ id: 21 });console.log(code, sdkID);// return {code, sdkID}// child表单提交成工后,触发parent页面提交if (code !== 200) return;console.log("++++++++++parent++++++++: parent页面表单提交成功后,调用child页面onFinishCallback方法");//parent页面提交任务结束后,通知child页面childRef.current.call("onFinishCallback", { parent_id: 2 });// 在parent页面注册finish-callback,等到该方法执行完成后,则完成一次iframe交互childRef.current.on("finish-callback", (data: any) => {console.log("++++++++++parent++++++++: 接收到child页面完成onFinishCallback通知",data);if (data?.code === 200) {setLoading(false);}});} catch (error) {console.log(error);}};return (Yay! Welcome to umi!
![]()
{ overflow: "hidden" }}>);
}export default HomePage;
子项目 vue
![]()
来自parent的信息:{{ JSON.stringify(formValues) }}
如果涉及到内嵌多个 iframe 的情况下,可参考以下 postmates-js 实现
https://gitee.com/videring/postmates-js