为iframe正名,你可能并不需要微前端

描述

 

任何新技术、新产品都是有一定适用场景的,它可能在当下很流行,但它不一定在任何时候都是最优解。

前言

最近几年微前端很火,火到有时候项目里面用到了iframe还要偷偷摸摸地藏起来生怕被别人知道了,因为担心被人质疑:你为什么不用微前端方案?直到最近笔者接手一个项目,需要将现有的一个系统整体嵌入到另外一个系统(一共20多个页面),在被微前端坑了几次之后,回过头发现,iframe真香!

qiankun的作者有一篇《Why Not Iframe》[1] 介绍了iframe的优缺点(不过作者还有一篇《你可能并不需要微前端》[2]给微前端降降火),诚然iframe确实存在很多缺点,但是在选择一个方案的时候还是要具体场景具体分析,它可能在当下很流行,但它不一定在任何时候都是最优解:iframe的这些缺点对我来说是否能够接受?它的缺点是否有其它方法可以弥补?使用它到底是利大于弊还是弊大于利?我们需要在优缺点之间找到一个平衡。

优缺点分析

代码

iframe适合的场景

由于iframe的一些限制,部分场景并不适合用iframe,比如像下面这种iframe只占据页面中间部分区域,由于父页面已经有一个滚动条了,为了避免出现双滚动条,只能动态计算iframe的内容高度赋值给iframe,使得iframe高度完全撑满,但这样带来的问题是弹窗很难处理,如果居中的话一般弹窗都相对的是iframe内容高度而不是屏幕高度,从而导致弹窗可能看不见,如果固定弹窗top又会导致弹窗跟随页面滚动,而且稍有不慎iframe内容高度计算有一点点偏差就会出现双滚动条。

代码

所以:

  • 如果页面本身比较简单,是一个没有弹窗、浮层、高度也是固定的纯信息展示页的话,用iframe一般没什么问题;
  • 如果页面是包含弹窗、信息提示、或者高度不是固定的话,需要看iframe是否占据了全部的内容区域,如果是像下图这种经典的导航+菜单+内容结构、并且整个内容区域都是iframe,那么可以放心大胆地尝试iframe,否则,需要慎重考虑方案选型。
代码

为什么一定要满足“iframe占据全部内容区域”这个条件呢?可以想象一下下面这种场景,滚动条出现在页面中间应该大部分人都无法接受:

代码

实战:A系统接入B系统

满足“iframe占据全部内容区域”条件的场景,iframe的几个缺点都比较好解决。下面通过一个实际案例来详细介绍将一个线上在运行的系统接入到另外一个系统的全过程。以笔者前段时间刚完成的ACP(全称Alibaba.com Pay,阿里巴巴国际站旗下一站式全球收款平台,下称A系统)接入生意贷(下称B系统)为例,已知:

  • ACP和生意贷都是MPA页面;
  • ACP系统在此之前没有接入其他系统的先例,生意贷是第一个;
  • 生意贷作为被接入系统,本次需要接入的一共有20多个页面,且服务端包含大量业务逻辑以及跳转控制,有些页面想看看长什么样子都非常困难,需要在Node层mock大量接口;
  • 接入时需要做功能删减,部分接口入参需要调整;
  • 生意贷除了接入到ACP系统中,之前还接入过AMES系统,本次接入需要兼容这部分历史逻辑;

我们希望的效果:

代码

假设我们新增一个页面 /fin/base.html?entry=xxx 作为我们A系统承接B系统的地址,A系统有类似如下代码:

class App extends React.Component {
    state = {
        currentEntry: decodeURIComponent(iutil.getParam('entry') || '') || '',
    };
    render() {
        return 
            "microFrontIframe" src={this.state.currentEntry}/>         
;     } }

隐藏原系统导航菜单

因为是接入到另外一个系统,所以需要将原系统的菜单和导航等都通过一个类似“hideLayout”的参数去隐藏。

前进后退处理

需要特别注意的是,iframe页面内部的跳转虽然不会让浏览器地址栏发生变化,但是却会产生一个看不见的“history记录”,也就是点击前进或后退按钮(history.forward()history.back())可以让iframe页面也前进后退,但是地址栏无任何变化。

所以准确来说前进后退无需我们做任何处理,我们要做的就是让浏览器地址栏同步更新即可。

如果要禁用浏览器的上述默认行为,一般只能在iframe跳转时通知父页面更新整个