> 文章列表 > qiankun应用级缓存-多页签缓存

qiankun应用级缓存-多页签缓存

qiankun应用级缓存-多页签缓存

需求:

A:主应用
B:子应用
项目框架:vue2 + 全家桶 + qiankun
应用间切换需要保存页面缓存(多页签缓存),通过vue keep-alive只能实现页面级缓存,在单独打开的应用里能实现缓存,但是子应用切换到主应用,那子应用的缓存失效
qiankun应用级缓存-多页签缓存

方案:

采用子应用切换时,将子应用作为一个vue实例,再次加载时使用保存的实例上的vnode替换vue实例化的时候的render函数

前提

1.项目已实现页面级缓存(其实就是通过keep-alive include来实现)

解决步骤

1.qiankun加载子应用的方式选择

1.通过registerMicroApps注册子应用,qiankun会通过自动加载匹配的子应用;
2.通过loadMicroApp手动注册子应用

第一种qiankun自动检测路有的变化来控制子应用的卸载和加载,我们无法监听到,也就无法去替换vnode,所以采用第二种,手动加载应用(通过路由的变化去监听下就行了)

//navbar。vau
watch: {$route(to, from) {//判断是否要加载 或卸载应用doQiankun(to, from)//这段代码时其他功能if (to.path.indexOf(ssoName) !== -1) {this.isShowssoAdmin = true} else {let timer = setTimeout(() => {this.isShowssoAdmin = falseclearTimeout(timer)})}}},//抽离的jsexport const doQiankun = (to, form) => {if (to.path.indexOf(ssoName) !== -1 && (form.path.indexOf(ssoName) === -1 || !form.path)) {loadApp()} else if (to.path.indexOf(ssoName) !== -1 && form.path.indexOf(ssoName) !== -1) {console.log('子应用之间切换')} else {unLoadApp()}
}export const loadApp = () => {// 手动加载微应用microApp = loadMicroApp({name: ssoName,entry: ssoUrl,container: `#${ssoName}`,props: { }})
}/*** @description: 手动卸载微应用* @return {*}* @Date Changed:*/
export const unLoadApp = () => {console.log('手动卸载微应用')// 手动卸载微应用if (microApp) microApp.unmount()
}

2.实现手动加载后,在子应用中unmount 卸载周期中存储实例

//main.js
//instance 其实就是new Vue()的实例
//loadedApplicationMap定义的对象
let loadedApplicationMap = {}
let instance = null
export async function unmount() {unmountCache(instance, loadedApplicationMap, instance.$router)router = null
}/*** @description: qiankun卸载子应用时 保存子应用实例* @param {*} instance  子应用实例* @param {*} loadedApplicationMap 保存的对象* @param {*} _router 离开时的路由* @return {*}* @Date Changed:*///代码都不用改  保存一下退出应用前的实例
function unmountCache(instance = {}, loadedApplicationMap = {}, _router) {// 此处永远只会保存首次加载生成的实例const needCached = instance.cachedInstance || instanceconst cachedInstance = {}cachedInstance._vnode = needCached._vnode// keepalive设置为必须 防止进入时再次created,同keep-alive实现if (!cachedInstance._vnode.data.keepAlive) cachedInstance._vnode.data.keepAlive = trueloadedApplicationMap._vnode = cachedInstance._vnodeloadedApplicationMap.$router = _routerloadedApplicationMap.apps = [].concat(_router.apps)loadedApplicationMap.currentRoute = { ..._router.currentRoute }}

3.进入应用时,替换vnode
这里要区分是否是首次进入

光替换node 会导致原来的路由失效,所以同时也要针对路有进行处理

//main.js
let isFirst = truefunction render(props = {}) {const { container } = props// 这里必须要new一个新的路由实例,否则无法响应URL的变化router = new VueRouter({// base: window.__POWERED_BY_QIANKUN__ ? '/ssoAdmin/' : '/',mode: 'hash',// mode: 'history',routes})// 这里主要是适配子应用的单独访问和继承访问let vnode = loadedApplicationMap._vnode || nullif (isFirst) {// 首次进入应用routerBeforeEach() //自己定义的路由守卫instance = newVueInstance(vnode).$mount(container ? container.querySelector('#app') : '#app')isFirst = false} else {//  router使用缓存命中// router = loadedApplicationMap.$router;// 让当前路由在最初的Vue实例上可用router.apps.push(...loadedApplicationMap.apps)routerBeforeEach() //自己定义的路由守卫instance = newVueInstance(vnode)// 当前路由和上一次卸载时不一致,则切换至新路由const { path } = router.currentRouteconst oldPath = loadedApplicationMap.currentRoute.pathif (path !== oldPath) {//replace 替换 浏览器记录loadedApplicationMap.$router.replace({ path, query: router.currentRoute.query })}instance.$mount(container ? container.querySelector('#app') : '#app')}
}