Postmate
一个强大的、简单的、基于 promise 的 postMessage iFrame 通信库。
Postmate 是一个建立在 postMessage 上的基于 promise 的 API。它允许父页面与子 iFrame 跨源对话,而且工作量很小。
你可以直接在 这里 下载编译后的 javascript。
特性
- 基于 promise 的 API,用于优雅和简单的通信。
- 安全的双向父 <-> 子握手,并带有消息验证。
- 子代暴露一个可检索的模型对象,父代可以访问。
- 子代发出事件,父代可以监听。
- 父代可以调用子代的函数。
- 零依赖性。如果需要的话,可以为 Promise API 提供自己的 polyfill 或抽象。
- 轻量级,大小约为1.6kb(缩小和压缩后)。
注意:虽然底层机制是 window.postMessage(),但只支持 iFrame。
安装
Postmate 可以通过 NPM 安装。
NPM
$ yarn add postmate # Install via Yarn
$ npm i postmate --save # Install via NPM
词汇表
- Parent:将嵌入 iFrame 的顶层页面,创建一个 Child。
- Child(子页面):在 iFrame 中加载的底层页面。iFrame 中加载的底层页面。
- Model(模型):子代向父代公开的对象。
- Handshake(握手):父框架向子框架标识自己的过程,反之亦然。当握手完成时,两个上下文已经绑定了它们的事件监听器并相互识别。
用法
- 父方开始与子方通信。发出握手,子方回应握手回复,完成父方/子方的初始化。两者进行绑定,准备进行安全通信。
- Parent 通过属性名从 Child 获取值。子代可以向父代发出消息。Parent 可以调用 Child 模型中的函数。
示例
parent.com
// Kick off the handshake with the iFrame const handshake = new Postmate({ container: document.getElementById('some-div'), // Element to inject frame into url: 'http://child.com/page.html', // Page to load, must have postmate.js. This will also be the origin used for communication. name: 'my-iframe-name', // Set Iframe name attribute. Useful to get `window.name` in the child. classListArray: ["myClass"] //Classes to add to the iframe via classList, useful for styling. }); // When parent <-> child handshake is complete, data may be requested from the child handshake.then(child => { // Fetch the height property in child.html and set it to the iFrames height child.get('height') .then(height => child.frame.style.height = `${height}px`); // Listen to a particular event from the child child.on('some-event', data => console.log(data)); // Logs "Hello, World!" });
child.com/page.html
const handshake = new Postmate.Model({ // Expose your model to the Parent. Property values may be functions, promises, or regular values height: () => document.height || document.body.offsetHeight }); // When parent <-> child handshake is complete, events may be emitted to the parent handshake.then(parent => { parent.emit('some-event', 'Hello, World!'); });
API
(恕删略。请参见自述文件。)
故障排除/常见问题
一般性问题
Q:为什么要使用 Promises 来做一个事件化的 API?
A:Promises 为获取数据提供了一个清晰的 API。使用事件化的方法往往是倒过来开始的。如果父节点想知道子节点的高度,子节点需要提醒父节点;而对于 Postmate,父节点将以类似于同步的方式向子节点请求该信息。对于那些仍然需要处理的其他用例,子程序也可以向父程序发出事件。
沉默的父/子程序
Q:我已经启用了日志记录功能,但父代或子代并没有记录所有信息。
A:Postmate.debug 需要在父代和子代中设置,以便它们各自记录各自的信息。
Q:子组件不响应来自父组件的通信
A:确保您已经在您的子页面中初始化了 Postmate.Model。
限制性交流
Q:我想通过子代来检索父代的信息。
A:Postmate(在设计上)在沟通模式上是有限制的。这强制了一种简单的方法:父节点负责父节点中包含的逻辑,子节点负责子节点中包含的逻辑。如果您需要从父 -> 子节点检索信息,请考虑在父节点中设置子节点可能扩展的默认模型。
Q:我想从父节点向子节点发送消息。
A:这就是 call 函数的具体作用。
安全性
Q:什么是握手,为什么我需要握手?
A:默认情况下,任何(父)页面收到的所有消息事件都可以来自任何(子)位置。这意味着父页必须始终在其消息事件中强制执行安全,确保子页(原点)是我们期望的人,消息是来自原始请求的响应,并且我们的消息是有效的。握手例程通过保存子代和父代的身份并确保不对其中任何一个进行更改来解决这个问题。
Q:消息是如何验证的?
A:请求的来源、消息类型、postMessage 的 mime 类型,以及某些情况下的消息响应,都会与握手完成时的原始数据进行验证。
许可证
MIT
(The first version translated by vz on 2020.11.21)