填坑小能手——页面缓存

前言

最近项目需求需要将页面进行缓存,这个需求直接用keep-alive就能实现。当时预估着很快就能完成需求,结果还是踩了一些的坑,大家将来如果有类似需求可以避免一下。

keep-alive

keep-alivevue的内置组件,不是vue-router的。使用keep-alive能够将当前页面进行缓存,再次进入页面不会触发页面mounted等生命周期,为了满足需要keep-alive有两个单独的生命周期:

js 复制代码
activated() {
    //加载时调用
  },
  deactivated() {
    //卸载后调用
  }

keep-alive的用法也很简单,将需要缓存的组件进行包裹即可,一般会跟router-view配合,包裹的router-view最好加个key值,路由地址对应的组件可能是同一个。

js 复制代码
<keep-alive>
 <router-view :key="key" />  //key可以为name或者pullPath
</keep-alive>

默认情况下keep-alive会缓存所有的组件,为了更加灵活的使用我们可以使用相关参数include与exclude参数。

js 复制代码
// include 包含 exclude排除
<keep-alive :include=cachedViews :exclude=notCached>
 <router-view :key="key" />
</keep-alive>

注意,接受的参数是组件name的集合 。实际开发中缓存一般是可控的,我们可以在路由配置项的meta中增加一个属性控制。

js 复制代码
{
path: '/home',
component: Home,
meta: { noCache: true }
},

cacheViews参数的值需要过滤掉noCache为true的值。

缓存不生效

前期工作准备完善,满怀期待打开页面,然后发现缓存不生效。网上查了查,缓存不生效的情况有以下几种:

  1. keep-alive位置放错,缓存的页面没被包裹进去。
  2. include参数里的name与组件名称没对齐。这里的name是组件名称,而不是路由名称
  3. 嵌套路由,这种算是第二种的特殊情况,我们会重点讲解下。

知道了原因,改起来就很快了。简单排查了下,发现项目中cachedViews添加的是路由名称:

js 复制代码
if (view.name === null) return
if (this.cachedViews.includes(view.name)) return
if (!view.meta.noCache) {
this.cachedViews.push(view.name)
}

再点开对应组件,发现没有name属性,难怪不生效,这就是第二种情况了,添加name属性为路由名称,再试下可以了。当我以为万事大吉的时候,发现某些页面还不生效,而这些页面都是有二级菜单也就是嵌套路由,嵌套路由多了一个router-veiw,这是个公共组件:

根据上面的原则,我把cachedViews中添加了'CommonRouterView',缓存生效了。但是这样子做所有子路由都会被缓存,noCache属性也就没啥用了,还得优化下。

嵌套路由缓存

当时在掘金上搜索了下,找到了比较靠谱的解决方案,就是将嵌套路由扁平化 ,变成一维数组,icludes里面跟一维数组对比,嵌套路由也就能被缓存了,不过文章中没列举出源码,想了下也就没深究。后面看到可以从原理上入手,keep-alive的原理中会通过唯一的key将组件进行缓存,而这个key就是组件名称,多级路由情况下组件名称不能满足使用,我们可以将key与路由相关属性结合起来,而路由的fullPath具有唯一性真合适。 修改起来也很简单,将keep-alive的源码复制一份出来,然后将关键代码进行修改:

用新写的缓存组件包裹router-view,然后将cachedViews的取值进行修改。

js 复制代码
cachedViews() {
// 添加修改为fullPath
if (!view.meta.noCache) {
this.cachedViews.push(view.fullPath)
})
}

如此key值相对应,嵌套路由能够正确缓存并且noCache也能够控制。

总结

页面缓存看似简单,但想要页面正确缓存还是需要注意细节的,尤其是碰到多级路由的情况。

相关推荐
NiceCloud喜云1 小时前
Opus 4.8 的 Effort Control 怎么选:Low 到 Max 五档策略
android·java·大数据·前端·c++·python·spring
wordbaby2 小时前
React Native + RNOH:跨页面数据回传的最佳实践与避坑指南
前端·react native
丷丩2 小时前
MapLibre GL JS第22课:查看本地GeoJSON
前端·javascript·map·mapbox·maplibre gl js
Front思3 小时前
AI前端工程师需要具备能力+
前端·人工智能·ai
ZC跨境爬虫5 小时前
跟着 MDN 学CSS day_29:(掌握文本与字体样式的核心艺术)
前端·css·ui·html·tensorflow
李子琪。6 小时前
网络空间安全深度实战:CSRF 漏洞原理剖析与基于 Token 的纵深防御体系构建(全栈实验报告)
前端·安全·csrf
冰暮流星6 小时前
javascript之history对象介绍
前端·笔记
IT_陈寒6 小时前
Vite热更新失灵?你可能漏了这个配置
前端·人工智能·后端
丷丩6 小时前
MapLibre GL JS第19课:实时更新要素
前端·javascript·gis·map·mapbox·maplibre gl js
Mr.Daozhi6 小时前
RAG 进阶实战:跑通 Demo 后我连续翻了 6 次车,逐一修复才真正可用(含 Gradio Web 版)
前端·数据库·langchain·大模型·gradio·rag·科研工具