From d3df7b6219e6c7857ae680d8d1dcd0afa3672714 Mon Sep 17 00:00:00 2001 From: rickcole Date: Mon, 20 Jul 2020 16:15:05 +0800 Subject: [PATCH 1/7] =?UTF-8?q?iframe=E6=94=AF=E6=8C=81=E9=80=9A=E4=BF=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/renderers/iFrame.md | 59 ++++++++++++++++++++++++++++++++++++++++ src/renderers/IFrame.tsx | 51 ++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/docs/renderers/iFrame.md b/docs/renderers/iFrame.md index 2bb43f4af..1952c1f20 100644 --- a/docs/renderers/iFrame.md +++ b/docs/renderers/iFrame.md @@ -11,3 +11,62 @@ } } ``` + +## 如何和 iframe 通信 + +#### amis 向 iframe 通信 + +在 iframe 页面中添加`message`事件监听器,在 iframe 初始化、更新、reload 的时候,会通过 `postMessage` 发送当前数据域数据,iframe 页面的事件监听器中可以通过`e.data`进行获取: + +```js +window.addEventListener('message', e => { + // e.data 获取当前数据域数据,进行使用 +}); +``` + +> 如果是 webpack 开发环境,注意过滤掉`webpackOk`类型消息 + +#### iframe 页面向 amis 通信 + +1. 首先在 amis 的 iframe 配置项中配置 events 对象,指明 iframe 需要触发的 amis 行为 + +```json +{ + "type": "iframe", + "src": "http://www.xxx.com", + "events": { + "detail": { + "actionType": "dialog", + "dialog": { + "title": "弹框", + "body": "iframe 传给 amis 的 id 是:${iframeId}" + } + } + } +} +``` + +上面 `events` 对象中配置了`detail`事件,该行为会触发 amis 弹框行为,并在弹框中渲染`"iframe 传给 amis 的 id 是:${iframeId}"`这段模板。 + +那么要如何触发该事件和传递数据呢? + +2. iframe 页面中,获取父级 window,并使用`postMessage`传递数据,格式如下: + +```js +window.parent.postMessage( + { + event: 'detail', + data: { + iframeId: '111' + } + }, + '*' +); +``` + +`message`格式: + +- `event`: 标识要触发的 amis 行为,这里我们设置为配置好的`detail`事件 +- `data`: 传给 amis 的数据,amis 会将该数据与当前数据域进行合并进行使用 + +这样 amis 弹框中就会渲染内容:`iframe 传给 amis 的 id 是:111` diff --git a/src/renderers/IFrame.tsx b/src/renderers/IFrame.tsx index 7e3fabedc..d790d78b9 100644 --- a/src/renderers/IFrame.tsx +++ b/src/renderers/IFrame.tsx @@ -4,10 +4,14 @@ import {filter} from '../utils/tpl'; import {autobind, createObject} from '../utils/helper'; import {ScopedContext, IScopedContext} from '../Scoped'; import {buildApi} from '../utils/api'; +import {ActionProps} from './Action'; export interface IFrameProps extends RendererProps { className?: string; src?: string; + events?: { + [eventName: string]: Object; + }; } export default class IFrame extends React.Component { @@ -20,6 +24,40 @@ export default class IFrame extends React.Component { frameBorder: 0 }; + componentDidMount() { + window.addEventListener('message', this.onMessage); + } + + componentDidUpdate(prevProps: IFrameProps) { + const data = this.props.data; + + if (data !== prevProps.data) { + this.postMessage(data); + } + } + + componentWillUnmount() { + window.removeEventListener('message', this.onMessage); + } + + @autobind + onMessage(e: MessageEvent) { + const {events, onAction, data} = this.props; + + if (!e.data || e.data === '' || !events) { + return; + } + + const action = events[e.data.event]; + action && onAction(e, action, createObject(data, e.data.data)); + } + + @autobind + onLoad() { + const {src, data} = this.props; + src && this.postMessage(data); + } + // 当别的组件通知 iframe reload 的时候执行。 @autobind reload(subpath?: any, query?: any) { @@ -34,6 +72,8 @@ export default class IFrame extends React.Component { src, data ).url; + + this.postMessage(data); } } @@ -47,9 +87,19 @@ export default class IFrame extends React.Component { src, createObject(data, values) ).url; + + this.postMessage(createObject(data, values)); } } + @autobind + postMessage(data: any) { + (this.IFrameRef.current as HTMLIFrameElement).contentWindow?.postMessage( + data, + '*' + ); + } + render() { let {className, src, width, height, frameBorder, data, style} = this.props; @@ -66,6 +116,7 @@ export default class IFrame extends React.Component { frameBorder={frameBorder} style={style} ref={this.IFrameRef} + onLoad={this.onLoad} src={src ? buildApi(src, data).url : undefined} /> ); From 4a8be8beb8ff6ffe8b88b3643fd9318dcce1d2c4 Mon Sep 17 00:00:00 2001 From: rickcole Date: Mon, 20 Jul 2020 16:15:53 +0800 Subject: [PATCH 2/7] fix --- src/renderers/IFrame.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/renderers/IFrame.tsx b/src/renderers/IFrame.tsx index d790d78b9..19b1d78e7 100644 --- a/src/renderers/IFrame.tsx +++ b/src/renderers/IFrame.tsx @@ -4,7 +4,6 @@ import {filter} from '../utils/tpl'; import {autobind, createObject} from '../utils/helper'; import {ScopedContext, IScopedContext} from '../Scoped'; import {buildApi} from '../utils/api'; -import {ActionProps} from './Action'; export interface IFrameProps extends RendererProps { className?: string; From aa314e7509ee6bb5487f030278b46e3d88b53958 Mon Sep 17 00:00:00 2001 From: rickcole Date: Tue, 21 Jul 2020 17:12:22 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=B8=80=E4=B8=8Biframe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/renderers/iFrame.md | 50 ++++++++++++++++++++++++++++++++++------ src/renderers/IFrame.tsx | 42 +++++++++++++++++++++++---------- 2 files changed, 73 insertions(+), 19 deletions(-) diff --git a/docs/renderers/iFrame.md b/docs/renderers/iFrame.md index 1952c1f20..52fa51c34 100644 --- a/docs/renderers/iFrame.md +++ b/docs/renderers/iFrame.md @@ -6,9 +6,7 @@ { "type": "iframe", "src": "raw:http://www.baidu.com", - "style": { - "height": 260 - } + "height": 300 } ``` @@ -16,7 +14,7 @@ #### amis 向 iframe 通信 -在 iframe 页面中添加`message`事件监听器,在 iframe 初始化、更新、reload 的时候,会通过 `postMessage` 发送当前数据域数据,iframe 页面的事件监听器中可以通过`e.data`进行获取: +在 iframe 页面中添加`message`事件监听器,在 iframe 初始化、更新或者接收到其他组件发送数据的时候,会通过 `postMessage` 发送当前数据域数据,iframe 页面的事件监听器中可以通过`e.data`进行获取: ```js window.addEventListener('message', e => { @@ -24,6 +22,23 @@ window.addEventListener('message', e => { }); ``` +`e.data` 格式及参数说明: + +```json +{ + "type": "amis:load", // 当前事件类型 + "data": { + //... 当前数据域数据 + } +} +``` + +- **type**: 当前事件类型 + - amis:load:初始化的时候触发 + - amis:update:组件更新时触发 + - amis:receive:组件通过 target 接收到其他组件发送来数据的时候 +- **data**:当前数据源数据 + > 如果是 webpack 开发环境,注意过滤掉`webpackOk`类型消息 #### iframe 页面向 amis 通信 @@ -50,12 +65,12 @@ window.addEventListener('message', e => { 那么要如何触发该事件和传递数据呢? -2. iframe 页面中,获取父级 window,并使用`postMessage`传递数据,格式如下: +2. iframe 页面中,获取父级 window,并使用`postMessage`传递数据,格式如下,: ```js window.parent.postMessage( { - event: 'detail', + type: 'amis:detail', data: { iframeId: '111' } @@ -66,7 +81,28 @@ window.parent.postMessage( `message`格式: -- `event`: 标识要触发的 amis 行为,这里我们设置为配置好的`detail`事件 +- `type`: 标识要触发的 amis 行为,请使用 `amis:xxx` 的格式,这里我们设置为配置好的`detail`事件 - `data`: 传给 amis 的数据,amis 会将该数据与当前数据域进行合并进行使用 这样 amis 弹框中就会渲染内容:`iframe 传给 amis 的 id 是:111` + +## 设置高度自适应 + +默认 amis 中只支持给 iframe 配置固定高度,我们可以通过上面说到的通信机制实现高度自适应。 + +1. 首先在 iframe 页面中获取到页面高度 +2. 通过`amis:resize`事件,将高度信息发送给 amis + +```js +window.parent.postMessage( + { + type: 'amis:resize', + data: { + height: 400 + } + }, + '*' +); +``` + +这样就可以动态设置 iframe 组件高度 diff --git a/src/renderers/IFrame.tsx b/src/renderers/IFrame.tsx index 19b1d78e7..909306205 100644 --- a/src/renderers/IFrame.tsx +++ b/src/renderers/IFrame.tsx @@ -18,11 +18,14 @@ export default class IFrame extends React.Component { static propsList: Array = ['src', 'className']; static defaultProps: Partial = { className: '', - width: '100%', - height: '100%', frameBorder: 0 }; + state = { + width: this.props.width || '100%', + height: this.props.height || '100%' + }; + componentDidMount() { window.addEventListener('message', this.onMessage); } @@ -31,7 +34,7 @@ export default class IFrame extends React.Component { const data = this.props.data; if (data !== prevProps.data) { - this.postMessage(data); + this.postMessage('update', data); } } @@ -47,14 +50,27 @@ export default class IFrame extends React.Component { return; } - const action = events[e.data.event]; - action && onAction(e, action, createObject(data, e.data.data)); + const [prefix, type] = e.data.type.split(':'); + + if (prefix !== 'amis' || !type) { + return; + } + + if (type === 'resize' && e.data.data) { + this.setState({ + width: e.data.data.width || '100%', + height: e.data.data.height || '100%' + }); + } else { + const action = events[type]; + action && onAction(e, action, createObject(data, e.data.data)); + } } @autobind onLoad() { const {src, data} = this.props; - src && this.postMessage(data); + src && this.postMessage('load', data); } // 当别的组件通知 iframe reload 的时候执行。 @@ -71,8 +87,6 @@ export default class IFrame extends React.Component { src, data ).url; - - this.postMessage(data); } } @@ -87,20 +101,24 @@ export default class IFrame extends React.Component { createObject(data, values) ).url; - this.postMessage(createObject(data, values)); + this.postMessage('receive', createObject(data, values)); } } @autobind - postMessage(data: any) { + postMessage(type: string, data: any) { (this.IFrameRef.current as HTMLIFrameElement).contentWindow?.postMessage( - data, + { + type: `amis:${type}`, + data + }, '*' ); } render() { - let {className, src, width, height, frameBorder, data, style} = this.props; + const {width, height} = this.state; + let {className, src, frameBorder, data, style} = this.props; style = { ...style From faf80abdcdabbcf2d0bfdf8ec7bcd6af22b2777f Mon Sep 17 00:00:00 2001 From: rickcole Date: Tue, 21 Jul 2020 17:33:07 +0800 Subject: [PATCH 6/7] change event name --- docs/renderers/iFrame.md | 2 +- src/renderers/IFrame.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/renderers/iFrame.md b/docs/renderers/iFrame.md index 52fa51c34..47f267a66 100644 --- a/docs/renderers/iFrame.md +++ b/docs/renderers/iFrame.md @@ -26,7 +26,7 @@ window.addEventListener('message', e => { ```json { - "type": "amis:load", // 当前事件类型 + "type": "amis:init", // 当前事件类型 "data": { //... 当前数据域数据 } diff --git a/src/renderers/IFrame.tsx b/src/renderers/IFrame.tsx index 909306205..edda5fb38 100644 --- a/src/renderers/IFrame.tsx +++ b/src/renderers/IFrame.tsx @@ -70,7 +70,7 @@ export default class IFrame extends React.Component { @autobind onLoad() { const {src, data} = this.props; - src && this.postMessage('load', data); + src && this.postMessage('init', data); } // 当别的组件通知 iframe reload 的时候执行。 From 4d1a750d00d1d8247c88b1d2d1218640da2a8aab Mon Sep 17 00:00:00 2001 From: rickcole Date: Tue, 21 Jul 2020 17:33:40 +0800 Subject: [PATCH 7/7] fix --- docs/renderers/iFrame.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/renderers/iFrame.md b/docs/renderers/iFrame.md index 47f267a66..9aa3158cd 100644 --- a/docs/renderers/iFrame.md +++ b/docs/renderers/iFrame.md @@ -34,7 +34,7 @@ window.addEventListener('message', e => { ``` - **type**: 当前事件类型 - - amis:load:初始化的时候触发 + - amis:init:初始化的时候触发 - amis:update:组件更新时触发 - amis:receive:组件通过 target 接收到其他组件发送来数据的时候 - **data**:当前数据源数据