手动控制子应用加载
qiankun默认提供可配置的引用加载方式, registerMicroApps 。 这种方式存在一些问题:
- 应用的切换取决于路由路径,且路由的切换将触发应用的卸载与加载, 例如: 从 A 切换到 B, 流程: 触发A unmount -> 判断 B 是否加载过, 未加载过:触发 bootstrap -> 触发 mount ,加载过: 直接触发 mount
- 如果子应用存在内部路由时, 内部路由跳转也将触发应用的重载。 可以看到应用的切换,将触发应用的重载,导致组件状态的丢失. 所以为了保持应用实例不会被反复加载,我们需要手动控制应用的声明周期
路由改造
主应用路由
代码语言:javascript复制// /root/router.js
// 子应用配置
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',
}
]
// 手动控制应用加载
import {loadMicroApp} from 'qiankun';
// 缓存应用实例
const microList = new Map([])
// 当前应用配置
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)
// 应用跳转
if(conf){
// 未切换子应用
if(current && current.activeRule === conf.activeRule ){
next()
return
}
const cacheMicro = microList.get(conf.activeRule)
// 已缓存应用
if(cacheMicro){
next()
return
}
// 未缓存应用
const micro = loadMicroApp({...conf, router})
microList.set(conf.activeRule, micro)
current = conf
next()
}
// 主应用内跳转
next()
})
子应用配置 keep-alive
代码语言:javascript复制因为需要缓存子应用,所以我们需要为每个子应用配置 keep-alive。 这里需要注意的地方是,需要将keep-alive 配置在子应用的 APP.vue 根路由下。 这里的子应用都配置在主应用的二,三级路由下,构造出的结构类似多级嵌套的父子路由关系。 所以这里子应用的 APP.vue 内的渲染入口变成了主应用的嵌套子路径, 2.0 使用方式
<keep-alive>
<router-view/>
</keep-alive>
3.0 使用方式
代码语言:javascript复制<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
例如:
代码语言:javascript复制// 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>