在之前的一篇文章中写了集中我用过的应用集成的方式,今天记录一下我在使用iframe集成方案的一些经验。
先说下优点:沙盒模式,各个子应用之前完全的独立的沙盒互不影响,不存样式、变量、依赖包等带来的问题;
缺点:跨域、通讯、独立的window窗口;
我们在使用iframe方案的时候。跨域主要是在服务端解决,比如nginx;通讯这部分开始制定好api,和带来的收益相比,维护成本还能接受;对于独window窗口带来的modal不居中、背景遮罩不全的问题,我们是舍弃了一部分体验的,这也是iframe集成方案最麻烦的一点;
我们在h5端也有尝试iframe的集成方案,也是因为历史债务问题,涉及到两个跨地区的款对,不得已选择了iframe方案,不过在维护和快速集成方面确实带来了很大的便利。
整体设计方案
路由
可以把每个子应用(iframe)封装成一个组件,切换路由是就是展示不同的组件。
这里有一个小技巧对应iframe来说,你可以把每个子应用都创建一个iframe,并且保持这个iframe不会被销毁,这样在下次进入子应用时,速度就很快了,只是改变一下iframe的url,并展示出来,在视觉上完全感受不到
举个例子(伪代码)
/**
* 内存允许的话,每一个子应用都是一个单例,缓存下来iframe,这样第二次加载就很快
*/
function FinanceSingletonIframe() {
// 控制iframe显示隐藏
const [show, setShow] = useState(false)
// 负责把父应用的路由转换成对应子应用的路由(iframe)
const iframePath = {
xxx: xxx
}
useEffect(() => {
// 监听路由变化
Router.onChange((router) => {
// 根据条件判断显示隐藏
if(['xxx', 'xxx'].indexOf(router.path) !== -1){
setShow(true)
}else{
setShow(false)
}
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<div style={{display: show ? 'blank' : 'none'}}>
<iframe
ref={iframeRef}
title="代账宝"
style={getIframeStyle()}
styleName="singleton-iframe"
src={iframePath[router.path]}
/>
</div>
);
}
export default FinanceSingletonContent;
通讯
维护一个事件中心,这个方案可选的有很多,比如原生的api postmessage
下面是一个简单的实现
父应用声明一套api
cost fn = {};
// 注册事件
function registerEvent(enentKey, fn){ fn[eventKey] = fn; }
// 删除事件
function unRegisterEvent(eventKey){ delete fn[eventKey] }
// 获取事件
function getEventFn(eventKey){ return fn[eventKey] }
// 调用事件
function invokeEvent(eventKey, param){ fn[eventKey](param) }
window.__EVENT_CENTER__ = {
registerEvent:registerEvent,
unRegisterEvent:unRegisterEvent,
getEventFn:getEventFn,
invokeEvent:invokeEvent
}
子应用
// 注册事件
window.top.__SERVYOU_DZB_H5__.registerEvent('test', () => {
// todo
});
// 触发事件
window.top.__SERVYOU_DZB_H5__.invokeEvent('goBack', argumentsList);
然后再约定好api命名、参数怎么传就可以了