mirror of
https://gitee.com/baidu/amis.git
synced 2024-12-02 11:58:10 +08:00
Merge remote-tracking branch 'baidu/master'
This commit is contained in:
commit
c8a56cb12d
@ -6,8 +6,103 @@
|
|||||||
{
|
{
|
||||||
"type": "iframe",
|
"type": "iframe",
|
||||||
"src": "raw:http://www.baidu.com",
|
"src": "raw:http://www.baidu.com",
|
||||||
"style": {
|
"height": 300
|
||||||
"height": 260
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 如何和 iframe 通信
|
||||||
|
|
||||||
|
#### amis 向 iframe 通信
|
||||||
|
|
||||||
|
在 iframe 页面中添加`message`事件监听器,在 iframe 初始化、更新或者接收到其他组件发送数据的时候,会通过 `postMessage` 发送当前数据域数据,iframe 页面的事件监听器中可以通过`e.data`进行获取:
|
||||||
|
|
||||||
|
```js
|
||||||
|
window.addEventListener('message', e => {
|
||||||
|
// e.data 获取当前数据域数据,进行使用
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
`e.data` 格式及参数说明:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "amis:init", // 当前事件类型
|
||||||
|
"data": {
|
||||||
|
//... 当前数据域数据
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- **type**: 当前事件类型
|
||||||
|
- amis:init:初始化的时候触发
|
||||||
|
- amis:update:组件更新时触发
|
||||||
|
- amis:receive:组件通过 target 接收到其他组件发送来数据的时候
|
||||||
|
- **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(
|
||||||
|
{
|
||||||
|
type: 'amis:detail',
|
||||||
|
data: {
|
||||||
|
iframeId: '111'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'*'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
`message`格式:
|
||||||
|
|
||||||
|
- `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 组件高度
|
||||||
|
@ -8,6 +8,9 @@ import {buildApi} from '../utils/api';
|
|||||||
export interface IFrameProps extends RendererProps {
|
export interface IFrameProps extends RendererProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
src?: string;
|
src?: string;
|
||||||
|
events?: {
|
||||||
|
[eventName: string]: Object;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class IFrame extends React.Component<IFrameProps, object> {
|
export default class IFrame extends React.Component<IFrameProps, object> {
|
||||||
@ -15,11 +18,61 @@ export default class IFrame extends React.Component<IFrameProps, object> {
|
|||||||
static propsList: Array<string> = ['src', 'className'];
|
static propsList: Array<string> = ['src', 'className'];
|
||||||
static defaultProps: Partial<IFrameProps> = {
|
static defaultProps: Partial<IFrameProps> = {
|
||||||
className: '',
|
className: '',
|
||||||
width: '100%',
|
|
||||||
height: '100%',
|
|
||||||
frameBorder: 0
|
frameBorder: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
width: this.props.width || '100%',
|
||||||
|
height: this.props.height || '100%'
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
window.addEventListener('message', this.onMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps: IFrameProps) {
|
||||||
|
const data = this.props.data;
|
||||||
|
|
||||||
|
if (data !== prevProps.data) {
|
||||||
|
this.postMessage('update', 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 [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('init', data);
|
||||||
|
}
|
||||||
|
|
||||||
// 当别的组件通知 iframe reload 的时候执行。
|
// 当别的组件通知 iframe reload 的时候执行。
|
||||||
@autobind
|
@autobind
|
||||||
reload(subpath?: any, query?: any) {
|
reload(subpath?: any, query?: any) {
|
||||||
@ -47,11 +100,25 @@ export default class IFrame extends React.Component<IFrameProps, object> {
|
|||||||
src,
|
src,
|
||||||
createObject(data, values)
|
createObject(data, values)
|
||||||
).url;
|
).url;
|
||||||
|
|
||||||
|
this.postMessage('receive', createObject(data, values));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
postMessage(type: string, data: any) {
|
||||||
|
(this.IFrameRef.current as HTMLIFrameElement).contentWindow?.postMessage(
|
||||||
|
{
|
||||||
|
type: `amis:${type}`,
|
||||||
|
data
|
||||||
|
},
|
||||||
|
'*'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
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 = {
|
||||||
...style
|
...style
|
||||||
@ -66,6 +133,7 @@ export default class IFrame extends React.Component<IFrameProps, object> {
|
|||||||
frameBorder={frameBorder}
|
frameBorder={frameBorder}
|
||||||
style={style}
|
style={style}
|
||||||
ref={this.IFrameRef}
|
ref={this.IFrameRef}
|
||||||
|
onLoad={this.onLoad}
|
||||||
src={src ? buildApi(src, data).url : undefined}
|
src={src ? buildApi(src, data).url : undefined}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user