Skip to main content

React中使用postMessage解决跨域传值及样式更改

简介

在平时开发中,除了与服务端客户端传值之外,我们前端传值也会面临一些传值的问题

  • 多窗口之间传值
  • 页面与嵌套的iframe消息传递

跨域解决之postMessage方式

发消息方调用 postMessage 方法发送消息 postMessage 是html5引入的API可以更方便、有效、安全的解决这些问题。postMessage() 方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。

收消息方用 MessageEvent 监听消息。

postMessage(data,origin) 方法接受两个参数

  • data:要传递的数据, html5 规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用JSON.stringify() 方法对对象参数序列化,在低版本IE中引用json2.js可以实现类似效果。
  • origin:字符串参数,指明目标窗口的源, 协议+主机+端口号[+URL],URL会被忽略,所以可以不写,这个参数是为了安全考虑,someWindow.postMessage() 方法只会在someWindow所在的源(url的protocol, host, port)和指定源一致时才会成功触发message
  • event,当然如果愿意也可以将参数设置为"*",someWindow可以在任意源,如果要指定和当前窗口同源的话设置为"/"。

MessageEvent的属性

  • data:顾名思义,是传递来的message
  • source:发送消息的窗口对象
  • origin:发送消息窗口的源(协议+主机+端口号)

同域/跨域父子页面间通讯

父页面

import React, { Component } from 'react';
import { autobind } from 'core-decorators';

export default class FatherPage extends Component {
componentDidMount() {
// 监听子页面发回的数据
window.addEventListener('message', this.receiveMessage);
// 父页面向子页面发送数据
this.refs.iframe.postMessage({style: '#000'}, '*');
}

@autobind
receiveMessage(e) {
if (e.data) {
console.log('from-son', e.data);
}
}

render() {
return (
<h1>Hello FatherPage!</h1>
<iframe
ref="iframe"
name="iframe"
id="iframe"
className="iframe-box"
style={{ height: 500 }}
src='/son-path'
/>
)
}
}

子页面

可以通过父页面传 style 来更改子页面样式

import React, { Component } from 'react';
import { observable } from 'mobx';
import { autobind } from 'core-decorators';
import { Button } from 'antd';

export default class SonPage extends Component {
@observable bg = '#fff';

componentDidMount() {
// 监听父页面发送的数据
window.addEventListener('message', this.receiveMessage);
}

@autobind
receiveMessage(e) {
if (e.data) {
console.log('from-father', e.data);
if(e.data.style) {
this.bg = e.data.style
}
}
}

@autobind
onTest() {
// 触发父页面的 message 事件 * 代表任何页面都可接收
window.top.postMessage('hi', '*');
}

render() {
return (
<h1 style={{backgroundColor: `${this.bg}`}}>Hello SonPage!</h1>
<Button onClick={this.onTest} type="primary">测试</Button>
)
}
}