手動控制子應(yīng)用加載
qiankun默認(rèn)提供可配置的引用加載方式, registerMicroApps 。
這種方式存在一些問題:
- 應(yīng)用的切換取決于路由路徑,且路由的切換將觸發(fā)應(yīng)用的卸載與加載, 例如: 從 A 切換到 B, 流程: 觸發(fā)A unmount -> 判斷 B 是否加載過, 未加載過:觸發(fā) bootstrap -> 觸發(fā) mount ,加載過: 直接觸發(fā) mount
- 如果子應(yīng)用存在內(nèi)部路由時, 內(nèi)部路由跳轉(zhuǎn)也將觸發(fā)應(yīng)用的重載。
可以看到應(yīng)用的切換,將觸發(fā)應(yīng)用的重載,導(dǎo)致組件狀態(tài)的丟失. 所以為了保持應(yīng)用實例不會被反復(fù)加載,我們需要手動控制應(yīng)用的聲明周期
路由改造
主應(yīng)用路由
// /root/router.js
// 子應(yīng)用配置
export const MICRO_CONF = [
{
name: 'app1',
entry: '//localhost:9001',
container: '#ROOT-CONTAINER-app1',
activeRule: '/home/app1',
},
{
name: 'app2',
entry: '//localhost:9002',
container: '#ROOT-CONTAINER-app2',
activeRule: '/home/app2'
},
{
name: 'app3',
entry: '//localhost:9003',
container: '#ROOT-CONTAINER-app3',
activeRule: '/home/app3',
}
]
// 手動控制應(yīng)用加載
import {loadMicroApp} from 'qiankun';
// 緩存應(yīng)用實例
const microList = new Map([])
// 當(dāng)前應(yīng)用配置
let current
const routes = [
{
path: '/',
redirect: {
path: '/home/*'
}
},
{
path: '/home/*',
name: 'Home',
component: Home,
}
]
const router = new VueRouter({
routes
})
router.beforeEach( async (to, from, next) =>{
const conf = MICRO_CONF.find(item => to.path.indexOf(item.activeRule) !== -1)
// 應(yīng)用跳轉(zhuǎn)
if(conf){
// 未切換子應(yīng)用
if(current && current.activeRule === conf.activeRule ){
next()
return
}
const cacheMicro = microList.get(conf.activeRule)
// 已緩存應(yīng)用
if(cacheMicro){
next()
return
}
// 未緩存應(yīng)用
const micro = loadMicroApp({...conf, router})
microList.set(conf.activeRule, micro)
current = conf
next()
}
// 主應(yīng)用內(nèi)跳轉(zhuǎn)
next()
})
子應(yīng)用配置 keep-alive
因為需要緩存子應(yīng)用,所以我們需要為每個子應(yīng)用配置 keep-alive。 這里需要注意的地方是,需要將keep-alive 配置在子應(yīng)用的 APP.vue 根路由下。
這里的子應(yīng)用都配置在主應(yīng)用的二,三級路由下,構(gòu)造出的結(jié)構(gòu)類似多級嵌套的父子路由關(guān)系。
所以這里子應(yīng)用的 APP.vue 內(nèi)的渲染入口變成了主應(yīng)用的嵌套子路徑,
2.0 使用方式
<keep-alive>
<router-view/>
</keep-alive>
3.0 使用方式
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
例如:
// micro-app1-vue3.0
// src/APP.vue
<template>
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
</template>
// micro-app2-vue2.0
// src/APP.vue
<template>
<keep-alive>
<router-view/>
</keep-alive>
</template>