微前端(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的方案,但是主应用有很多子应用页面,不可能每个都那么处理的

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

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

相关推荐
kyriewen1 小时前
百度用6%成本碾压硅谷?中国AI把性价比玩明白了
前端·百度·ai编程
kyriewen1 小时前
你还在手动敲命令部署?GitHub Actions 让你 push 即上线,摸鱼时间翻倍
前端·面试·github
Csvn3 小时前
Pinia 状态管理
前端
不减20斤不改头像3 小时前
手机一句话开发贪吃蛇!TRAE SOLO 移动端 AI 编程实测
前端·后端
xuankuxiaoyao3 小时前
Vue.js实践-组件基础下
前端·javascript·vue.js
一棵白菜4 小时前
Claude Code + Amazon Bedrock 使用指南
前端
大家的林语冰4 小时前
前端周刊:axios 疑遭朝鲜黑客“钓鱼“;CSS 新函数上线;npm 上线深色主题;Oxlint 兼容表;ESLint 支持 Temporal......
前端·javascript·css
哀木5 小时前
一个简单的套壳方案,就能让你的 Agent 少做重复初始化
前端
问心无愧05136 小时前
ctf show web入门27
前端
小村儿6 小时前
给 AI Agent 装上"长期记忆":Karpathy 的 LLM Wiki 思想,我做成了工具
前端·后端·ai编程