公司平台涉及自研和外采等多个子系统,如何把众多子系统前端界面集成到一起,组成统一平台管理界面,最大程度地提升保持用户体验一致,是项目团队首要解决的问题,在传统iframe方案不能满足项目需求情况下,经过反复技术对比,最终确定运用qiankun框架解决目前任务需求。
一、为啥要选择qiankun框架?
使用了qiankun框架你可以做到:
- 在同一个页面中使用多种技术框架(React, Vue, AngularJS, Angular, Ember等任意技术框架),并且不需要刷新页面.
- 无需(无需重构现有代码)使用新的技术框架编写代码,现有项目中的代码无需重构.
- (更优的性能)每个独立模块的代码可做到按需加载,不浪费额外资源.
- 每个独立模块可独立运行.
而传统的iframe :
- 页面加载问题: 影响主页面加载,阻塞onload事件,本身加载也很慢,页面缓存过多会导致电脑卡顿。(无法解决)
- 布局问题:iframe必须给一个指定的高度,否则会塌陷。
- 弹窗及遮罩层问题:只能在iframe范围内垂直水平居中,没法在整个页面垂直水平居中。
- 浏览器前进/后退问题:iframe页面刷新会重置(比如说从列表页跳转到详情页,然后刷新,会返回到列表页),因为浏览器的地址栏没有变化。
- iframe的页面跳转到其他页面出问题,比如两个iframe之间相互跳转,直接跳转会只在iframe范围内进行。
但qiankun框架也有一些需要注意项,css和js需要制定规范进行隔离。否则容易造成全局污染,尤其是vue的全局组件,全局钩子。还有qiankun不适用< ie9 以下的版本。
二、qiankun框架
qiankun(乾坤)框架其实是基于single-spa框架搭建而成的,简单来说就是single-spa的优化版。
(图为qiankun架构)
进入app1应用时, 由于vue-router配置的作用,默认地址栏后加了个/app1,但实际加载的app1是跑在localhost: 8081上的
进入app2应用时,同理地址栏后加了个/app2,但实际加载的app2是跑在localhost: 8082上的
大体实现思路
1. 预加载资源 如果在应用注册配置中,有配置需要预加载的应用,则在初始化的同时去加载这些应用。
- 初始化路由 根据配置的路由规则,与当前页面路径匹配,找到当前有效的应用信息。并且通过popstate监听页面路由变化,根据路由变化得到当前有效的应用
3. 代理部分window事件 由于每个应用可能各自会绑定一些window事件,因此劫持window.addEventListener,将每个应用所绑定的事件记录下来,方便后续再切换路由时清除掉。
4. 加载资源 目通过加载目标页面,分析各种资源然后加载执行
5. 记录全局变量 在每个应用执行之前,记录当前全局变量,然后在应用被卸载的时候,清除掉所有全局变量,以免影响下个应用的执行。
相关知识点
a、沙盒模型
qiankun有一个沙盒模型,我们知道所有的全局的方法、全局的变/常量和全局对象都属于window对象,而能导致js污染的也就是这些全局的方法和对象。它能够在子系统加载之前对window对象做一个快照(拷贝),然后在子系统卸载的时候恢复这个快照,即可以保证每次子系统运行的时候都是一个全新的window对象环境。其实大致原理就是记录window对象在子系统运行期间新增、修改和删除的属性和方法,然后会在子系统卸载的时候复原这些操作。
b、css污染它是如何解决的
它解决css污染的办法是:在子系统卸载的时候,将子系统引入css使用的<link>、<style>标签移除掉。移除的办法是重写<head>标签的appendChild方法,办法类似定时器的重写。子系统加载时,会将所需要的js/css文件插入到<head>标签,而重写的appendChild方法会记录所插入的标签,然后子系统卸载的时候,会移除这些标签。
c、子系统预请求是如何实现的
我们需要知道子系统有哪些js/css需要加载,而借助systemJs加载子系统,只知道子系统的入口文件(app.js)。qiankun不仅支持app.js作为入口文件,还支持index.html作为入口文件,它会用正则匹配出index.html里面的js/css标签,然后实现预请求。
总结
qiankun框架几乎满足了所有需求,但也有美中不足的,如组件间通信问题随着业务复杂随之也变得难以管理,以及兼容性的问题,这也是后面需进一步提升解决的。