公司平台涉及自研和外采等多個子系統,如何把眾多子系統前端界面集成到一起,組成統一平台管理界面,最大程度地提升保持用戶體驗一致,是項目團隊首要解決的問題,在傳統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框架幾乎滿足了所有需求,但也有美中不足的,如組件間通信問題隨着業務復雜隨之也變得難以管理,以及兼容性的問題,這也是后面需進一步提升解決的。