微前端(qiankun)多页签方案动态路由缓存问题

前言:

因为前期一直在做低码平台,里面有编辑页面跟预览页面,最近新加的需求是,这俩页面是动态路由,需要做缓存处理,并且集成到微前端主应用。

注意:阅读此文章前,需要对keep-alive原理跟微前端有一定的了解哦!

keep-alive源码解析

js 复制代码
<keep-alive :include="cachedViews">
  <router-view :key="key" />
</keep-alive> 

include数组,数组里面包裹的是组件name,(它是一个抽象组件,打开vue调试工具你没法看到这个组件的显示。建议集成组件做个扩展,将它改成非抽象组件,如下图,你可以看到keep-alive内部参数)只有name在这个数组中的组件才会被缓存,不然会把对应的已缓存的组件实例销毁。key是组件缓存用来保存缓存组件实例用的key值,当你点击tag时,会根据对应的key取出对应的组件实例进行显示(具体看源码吧,或者别的解析文章,这个原理一定要懂,不然后面的内容可能不太容易理解)

js 复制代码
// keep-alive缓存源码
// 地址:https://github.com/vuejs/vue/blob/main/src/core/components/keep-alive.ts#L69
cacheVNode() {
  const { cache, keys, vnodeToCache, keyToCache } = this
  if (vnodeToCache) {
    const { tag, componentInstance, componentOptions } = vnodeToCache
    cache[keyToCache] = {
      name: _getComponentName(componentOptions),
      tag,
      componentInstance
    }
    keys.push(keyToCache)
    // prune oldest entry
    if (this.max && keys.length > parseInt(this.max)) {
      pruneCacheEntry(cache, keys[0], keys, this._vnode)
    }
    this.vnodeToCache = null
  }
}
},

问题:关闭tag会导致动态路由页面缓存失效

由此可见,动态路由keep-alive是可以缓存的,你传入的key为路由的path就行,但是呢,我们因为做了多页签处理,所以就碰到一个很难受的问题,keep-alive的include的数组保存的组件name,动态路由只是path不一样,但是name是一样的,所以当你关闭一个tag时,会删除页签数组中的对应的组件的name,而这个数组是传入到keep-alive的include的数组,那这样会把name相同但是path不同的组件全都销毁了,缓存就会失效。

微前端多页签缓存方案解析(简洁版)

现在的主应用布局组件Layout结构如下图:

  • 解释一下:layout组件是主应用使用的布局组件,tag-view是多页签组件,AppMain是包裹子应用的主内容区组件。目前layout组件为了实现缓存页面,在 app-main 主内容区有keep-alive 组件,要在多层路由中都能缓存则需要多层 keep-alive 组件(注意:子主应用各自有自己的一套路由,比如编辑页面,主应用编辑页路由name是Edit,子应用编辑页路由的name也是Edit,它俩的path要一致),所以子应用也有对应的keep-alive包裹。
  • 当主应用删除一个tag时,会删除对应的组件name,并且会将删除的组件的path通知到子应用,子应用拿到path找到对应组件的name,将缓存的include中的name删除。
  • 问题来了,动态路由name是一样的呀,上面有说到,就是你打开多个编辑页,你只要删了其中一个tag,那就会触发多次组件销毁,并通知多次到子应用,子组件对应的也是会去删除include中的name,也会导致缓存直接失效了。

解决方案

主应用:

  1. 继承keep-alive组件,创建KeepAliveManuallyCache组件,设置组件为非抽象组件,设置ref,并在内部封装一个函数clearCacheByKey(参数是route的path),这个函数的作用是用于手动删除缓存
  2. tag关闭时,抛出一个删除事件到layout组件,监听这个方法,删除事件触发时,拿到KeepAliveManuallyCache的ref,并调用clearCacheByKey,销毁对应path的组件实例(clearCacheByKey的实现参考keep-alive源码中的pruneCacheEntry的方法)
  3. 设置一个标志,在使用KeepAliveManuallyCache组件进行显示时,不要去删除对应的缓存中的组件name(删了缓存就失效了,理由上面有说)
  4. 在原来使用keep-alive的地方,使用component 组件渲染,暴露keepAliveName字段,让用户自主传入keep-alive的名称,进行渲染

子应用:

  1. 因为keep-alive是根据include的值name去决定组件缓存的,不在include中的组件,会被销毁,所以子组件更简单一点的解决方案是,动态添加路由,在点击编辑进行跳转之前将编辑页组件的name重写,生成动态的name的组件,比如Edit-${id},这样在关闭tag的时候,由于每个编辑页的name是唯一的,所以不会把所有的编辑页的实例给销毁
  2. 预览页同上
  3. 其实主应用也可以采用1的方案,但是主应用有很多子应用页面,不可能每个都那么处理的

这样问题就解决了,嘿嘿嘿!!!

最后,感谢大家阅读我的小文章,请帮我点亮一下我的小心心吧!!!

相关推荐
工业互联网专业3 分钟前
毕业设计选题:基于springboot+vue+uniapp的驾校报名小程序
vue.js·spring boot·小程序·uni-app·毕业设计·源码·课程设计
J不A秃V头A32 分钟前
Vue3:编写一个插件(进阶)
前端·vue.js
司篂篂1 小时前
axios二次封装
前端·javascript·vue.js
姚*鸿的博客1 小时前
pinia在vue3中的使用
前端·javascript·vue.js
宇文仲竹2 小时前
edge 插件 iframe 读取
前端·edge
Kika写代码2 小时前
【基于轻量型架构的WEB开发】【章节作业】
前端·oracle·架构
天下无贼!3 小时前
2024年最新版Vue3学习笔记
前端·vue.js·笔记·学习·vue
Jiaberrr3 小时前
JS实现树形结构数据中特定节点及其子节点显示属性设置的技巧(可用于树形节点过滤筛选)
前端·javascript·tree·树形·过滤筛选
赵啸林3 小时前
npm发布插件超级简单版
前端·npm·node.js
罔闻_spider4 小时前
爬虫----webpack
前端·爬虫·webpack