前言
最近产品要求开发了一个pc端预览移动端的页面,要求移动端的预览页需要是真实的移动端页面;且移动端预览页上需要响应pc端上的各种操作,例如移动端里的某个节点隐藏或显示,或者是pc端上配置数据变了,移动端预览页也需要同事响应;好吧,那就产品说啥就是啥,干就完事了╮(╯▽╰)╭;考虑到pc端用的是UI框架是antd,移动端用用的ui框架是antd-mobile写的,最终决定用Iframe来预览移动端的页面;
采用Iframe的方式来预览移动端页面的话,面临几个问题,
- 父容器的页面和子容器页面之间数据的同步
- 父容器和子容器的跨域通讯问题
为了解决这几个问题,查询了Iframe 的相关资料,发现利用postMessage可以进行iframe跨域通信,postMessage可以解决父容器和子容器之间的信息通讯问题;
1. 父容器接收子容器的信息
useEffect(() => {
window.addEventListener('message', receiveMessgeFromSun, false);
return () => {
window.removeEventListener('message', receiveMessgeFromSun);
};
}, [visible]);
const receiveMessgeFromSun = (e) => {
if (e.data?.type === 'layout-change') {
const { current, layouts, curTabsWidget = {} } = e.data?.data || {};
onLayoutChange(current, layouts, curTabsWidget);
}
if (e.data?.type === 'hide-widget') {
const { hideItem } = e.data?.data || {};
toHideWidget(hideItem);
}
};
2. 子容器接收父容器信息
useEffect(() => {
if (dashboardId === undefined) {
window.addEventListener('message', receiveMessgeFromFather, false);
}
return () => {
if (dashboardId === undefined) {
window.removeEventListener('message', receiveMessgeFromFather);
}
};
}, []);
const receiveMessgeFromFather = e => {
if (e.data?.type === 'widgets-change') {
const { widgetItem, widgets, baseConfig } = e.data?.data || {};
receiveQueryByDefault(widgets);
widgets && setWidgets(widgets);
widgetItem && setWidgetItem(widgetItem);
baseConfig && globalStyleDetail(baseConfig);
}
};
3. 子容器向父容器发送信息
const sendMessageToFather = ({type, data}) => {
window.parent.postMessage({
type,
data
}, '*');
};
4. 父容器向子容器发送信息
// 给Iframe发送消息
sendMessageToIframe = ({type, data }) => { console.log(type, data);
this.iframeRef.current.contentWindow.postMessage({
type,
data
}, '*');
}