news 2026/7/11 9:53:50

Vue keep-alive 实战避坑:include/exclude + 路由 meta 标记,中后台路由缓存精准可控|状态管理与路由规范篇

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue keep-alive 实战避坑:include/exclude + 路由 meta 标记,中后台路由缓存精准可控|状态管理与路由规范篇

【Vue keep-alive】+【中后台路由缓存】:从include/exclude控制到路由meta标记,彻底搞懂页面缓存可控方案,避开组件无name、层级错误等高频坑!

📑 文章目录

  • 一、先搞清楚:为什么要用 keep-alive?
  • 二、基础用法:最简单的 keep-alive
    • 2.1 在路由出口处包一层
  • 三、include / exclude:精确控制「谁缓存、谁不缓存」
    • 3.1 参数说明
    • 3.2 用 include 做白名单
    • 3.3 用 exclude 做黑名单
    • 3.4 关键点:组件必须有 name
    • 3.5 常见坑:name 要和 include/exclude 里的完全一致
  • 四、路由 meta 标记:可维护性更好的方式
    • 4.1 路由配置
    • 4.2 根据 meta 动态计算 include
    • 4.3 Vue 2 中的写法
  • 五、更完整的实战结构:多级路由 + keep-alive
    • 5.1 目录结构示例
    • 5.2 路由配置
    • 5.3 MainLayout.vue 中的 keep-alive
    • 5.4 子组件必须定义 name
  • 六、生命周期:activated 与 deactivated
    • 6.1 典型用法:刷新列表、恢复滚动
  • 七、常见问题与避坑
  • 八、推荐规范小结
  • 九、小结
  • 🔍 系列模块导航

同学们好,我是 Eugene(尤金),一名多年中后台前端开发工程师。

(Eugene 发音 /juːˈdʒiːn/,大家怎么顺口怎么叫就好)

很多前端开发者都会遇到一个瓶颈:

代码能跑,但不够规范;功能能实现,但维护起来特别痛苦;一个人写没问题,一到团队协作就各种混乱、踩坑、返工。

想写出干净、优雅、可维护的专业代码,靠的不是天赋,而是体系化的规范 + 真实实战经验

这一系列《前端规范实战》,我会用大白话 + 真实业务场景,不讲玄学、不堆理论,只分享能直接落地的规范、标准与避坑指南。

帮你从「会写代码」真正升级为「会写优质、可维护、团队级别的代码」。


一、先搞清楚:为什么要用 keep-alive?

日常写 Vue 项目时,从列表进详情再返回,页面会重新渲染,数据和滚动位置都会丢失,用户体验很差。

keep-alive的作用就是:把匹配到的组件缓存在内存里,切换路由时不会销毁,而是保持上一次的状态。再返回时,数据、滚动条、表单输入都会保留。

  • 适合做缓存的:列表页、搜索结果、表单(多步骤)、数据统计/图表等需要保留状态的页面。
  • 不适合缓存的:登录页、404、纯静态说明页等。

⬆ 返回目录


二、基础用法:最简单的 keep-alive

2.1 在路由出口处包一层

<!-- App.vue 或根布局组件 --><template><divid="app"><router-viewv-slot="{ Component }"><keep-alive><component:is="Component"/></keep-alive></router-view></div></template>

这样写会缓存所有路由组件,简单但不可控,一般不推荐。

⬆ 返回目录


三、include / exclude:精确控制「谁缓存、谁不缓存」

3.1 参数说明

参数类型说明
includeStringRegExp
excludeStringRegExp
maxNumber最多缓存多少个组件,超出按 LRU 策略淘汰

这里的「名称」指的是组件的name选项,不是路由的pathmeta

⬆ 返回目录

3.2 用 include 做白名单

<template><router-viewv-slot="{ Component }"><keep-alive:include="['ProductList', 'OrderList', 'Dashboard']"><component:is="Component"/></keep-alive></router-view></template>

只有nameProductListOrderListDashboard的组件会被缓存,其余不缓存。

⬆ 返回目录

3.3 用 exclude 做黑名单

<template><router-viewv-slot="{ Component }"><keep-aliveexclude="LoginPage,NotFound"><component:is="Component"/></keep-alive></router-view></template>

nameLoginPageNotFound的组件不会被缓存。

⬆ 返回目录

3.4 关键点:组件必须有 name

<scriptsetup>defineOptions({name:'ProductList'// 必须!否则 include/exclude 无法匹配})</script><template><div>商品列表页</div></template>

如果组件没有nameinclude/exclude对它是无效的。

⬆ 返回目录

3.5 常见坑:name 要和 include/exclude 里的完全一致

// ❌ 错误:路由配置里的 component 没有 name{path:'/product/list',component:()=>import('@/views/ProductList.vue')}// ProductList.vue 里必须写 defineOptions({ name: 'ProductList' })// ✅ 正确:组件 name 和 include 数组里的字符串完全一致// keep-alive :include="['ProductList']"// ProductList.vue: defineOptions({ name: 'ProductList' })

⬆ 返回目录


四、路由 meta 标记:可维护性更好的方式

通过路由的meta标记「是否需要缓存」,比在keep-alive里硬编码include数组更清晰,也更易维护。

4.1 路由配置

// router/index.jsconstroutes=[{path:'/product/list',name:'ProductList',component:()=>import('@/views/ProductList.vue'),meta:{keepAlive:true}// 标记为需要缓存},{path:'/product/detail/:id',name:'ProductDetail',component:()=>import('@/views/ProductDetail.vue'),meta:{keepAlive:false}// 详情页一般不缓存},{path:'/login',name:'Login',component:()=>import('@/views/Login.vue'),meta:{keepAlive:false}}]

⬆ 返回目录

4.2 根据 meta 动态计算 include

<!-- App.vue --><template><router-viewv-slot="{ Component, route }"><keep-alive:include="cachedViews"><component:is="Component":key="route.path"/></keep-alive></router-view></template><scriptsetup>import{computed}from'vue'import{useRouter}from'vue-router'constrouter=useRouter()// 从路由配置中筛选出 meta.keepAlive === true 的组件名constcachedViews=computed(()=>{returnrouter.getRoutes().filter(route=>route.meta?.keepAlive&&route.name).map(route=>route.name)})</script>

这样,只要在路由里改meta.keepAlive,就能控制哪些页面被缓存,不用再去改keep-alive的配置。

⬆ 返回目录

4.3 Vue 2 中的写法

computed:{cachedViews(){returnthis.$router.options.routes.filter(route=>route.meta?.keepAlive&&route.name).map(route=>route.name)}}

⬆ 返回目录


五、更完整的实战结构:多级路由 + keep-alive

很多项目会区分「有布局的页面」和「无布局的页面」,布局里再包一层router-view,需要把keep-alive放在正确的层级。

5.1 目录结构示例

views/ ├── layout/ │ └── MainLayout.vue # 主布局,包含侧边栏 + 内容区 ├── product/ │ ├── ProductList.vue # 商品列表(缓存) │ └── ProductDetail.vue # 商品详情(不缓存) └── Login.vue # 登录(不缓存)

⬆ 返回目录

5.2 路由配置

constroutes=[{path:'/login',component:()=>import('@/views/Login.vue'),meta:{keepAlive:false}},{path:'/',component:()=>import('@/views/layout/MainLayout.vue'),children:[{path:'product/list',name:'ProductList',component:()=>import('@/views/product/ProductList.vue'),meta:{keepAlive:true,title:'商品列表'}},{path:'product/detail/:id',name:'ProductDetail',component:()=>import('@/views/product/ProductDetail.vue'),meta:{keepAlive:false,title:'商品详情'}}]}]

⬆ 返回目录

5.3 MainLayout.vue 中的 keep-alive

<!-- views/layout/MainLayout.vue --><template><divclass="main-layout"><asideclass="sidebar">...</aside><mainclass="content"><router-viewv-slot="{ Component, route }"><keep-alive:include="cachedViews"><component:is="Component":key="route.path"/></keep-alive></router-view></main></div></template><scriptsetup>import{computed}from'vue'import{useRouter}from'vue-router'constrouter=useRouter()constcachedViews=computed(()=>{// 只处理当前 layout 下的 children,避免把 Login 等算进来constlayout=router.getRoutes().find(r=>r.path==='/')if(!layout?.children)return[]returnlayout.children.filter(route=>route.meta?.keepAlive&&route.name).map(route=>route.name)})</script>

⬆ 返回目录

5.4 子组件必须定义 name

<!-- ProductList.vue --><scriptsetup>defineOptions({name:'ProductList'})</script>

⬆ 返回目录


六、生命周期:activated 与 deactivated

keep-alive缓存的组件,不会反复触发mounted/unmounted,而是使用:

  • activated:组件被激活(从别的路由切回来时)
  • deactivated:组件被停用(切走时)

6.1 典型用法:刷新列表、恢复滚动

<scriptsetup>import{ref,onActivated}from'vue'import{useRoute}from'vue-router'constlist=ref([])constscrollTop=ref(0)constroute=useRoute()// 首次进入或从详情返回,都可以在这里刷新onActivated(()=>{loadList()nextTick(()=>{listRef.value?.scrollTo(0,scrollTop.value)})})// 离开时保存滚动位置onDeactivated(()=>{scrollTop.value=listRef.value?.scrollTop??0})asyncfunctionloadList(){constres=awaitfetchList(route.query)list.value=res.data}</script>

⬆ 返回目录


七、常见问题与避坑

7.1 缓存了不该缓存的页面

现象:登录后退出,再进登录页,还能看到上次的账号。
原因:登录页被keep-alive缓存了。
处理:在excludemeta.keepAlive里排除登录页,并确保组件有正确的name

7.2 以为缓存了,实际没缓存

现象:列表页返回后数据丢失。

排查

  1. 组件是否定义了name
  2. name是否和include/cachedViews中完全一致;
  3. keep-alive是否包在了正确的router-view外层(多级路由时)。

7.3 多 Tab 页只缓存一个

现象:有多个 Tab,切换后只保留最后一个的状态。
原因:多个 Tab 可能共用同一个路由path,没有用key区分实例。
处理:给component加不同的key,例如:

<component:is="Component":key="route.fullPath"/>

这样同一路由的不同参数会当成不同组件实例进行缓存。

7.4 缓存的页面需要「按需刷新」

可以在meta里加标识,或在activated里根据条件决定是否重新请求:

// 方式1:meta 里标记meta:{keepAlive:true,refreshOnActivate:true}// 方式2:activated 里判断onActivated(()=>{if(route.query.refresh==='1'){loadList()}})

⬆ 返回目录


八、推荐规范小结

场景建议做法
缓存策略用路由meta.keepAlive控制,避免在模板里硬编码
组件名每个页面组件都定义name,且和路由name保持一致
keep-alive 位置放在实际渲染页面的router-view外层(多级路由时注意层级)
列表页activated中按需刷新,用deactivated保存滚动位置
登录 / 404 等一律meta.keepAlive: false或加入exclude

⬆ 返回目录


九、小结

keep-alive的核心就是三件事:

  1. include / exclude:通过组件name决定缓存范围;
  2. meta.keepAlive:用路由配置统一管理,方便维护;
  3. activated / deactivated:在缓存组件里做刷新和状态恢复。

记住:组件必须写name,否则include/exclude不会生效。结合路由meta和生命周期,就可以把缓存控制得清晰、可控。

⬆ 返回目录

🔍 系列模块导航

📝 状态管理与路由规范

一、《Vue3 Pinia 状态管理规范:状态拆分、Actions 写法、持久化实战,避坑状态污染|状态管理与路由规范篇》
二、《Vue3 Pinia 状态管理规范:何时用 Pinia 何时用本地状态|状态管理与路由规范篇》
三、《Vue Router 实战规范:path/name/meta 配置 + 动态 / 嵌套路由,统一团队标准|状态管理与路由规范篇》
四、《Vue3 + Vue Router + Pinia 路由守卫规范:beforeEach 应做 / 不应做,避死循环、防重复请求|状态管理与路由规范篇》
五、《Vue keep-alive 实战避坑:include/exclude + 路由 meta 标记,中后台路由缓存精准可控|状态管理与路由规范篇》

👉 跟着系列慢慢学,把技术功底扎扎实实地打牢~

📚 系列总览

前端规范实战系列」正在持续更新中,后续会整理一篇《前端规范实战系列全系列目录导航》,包含每篇文章简介 + 直达链接,方便大家按顺序、体系化学习。

更新中,敬请期待~

⬆ 返回目录


技术成长,从来不是比谁写得快,而是比谁写得稳、规范、可维护

哪怕每次只吃透一条规范,长期下来,差距会非常明显。

后续我会持续更新前端规范、工程化、可维护代码相关实战干货,帮你告别面条代码、维护噩梦,在开发与面试中更有底气。

觉得有用欢迎点赞 + 收藏 + 关注,不错过每一篇实战内容。

我是 Eugene,与你一起写规范、写优质代码,我们下篇干货见~

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/7 7:30:09

Python实战:用SciPy和NumPy解常微分方程(ODE)的5种常用方法

Python实战&#xff1a;用SciPy和NumPy解常微分方程&#xff08;ODE&#xff09;的5种常用方法 常微分方程&#xff08;ODE&#xff09;在工程仿真、物理建模和生物动力学中无处不在。作为Python开发者&#xff0c;掌握SciPy和NumPy这两个科学计算核心库的ODE求解能力&#xff…

作者头像 李华
网站建设 2026/7/7 18:31:03

企业如何有效利用高防服务器

在当今数字化商业环境中&#xff0c;企业的网络业务面临着诸多安全威胁&#xff0c;如DDOS 攻击和CC 攻击等常见的网络威胁&#xff0c;这些攻击可能导致企业网站瘫痪、业务中断、数据泄露等严重后果。 而高防服务器凭借其强大的防护能力&#xff0c;成为企业保障网络安全、稳…

作者头像 李华
网站建设 2026/7/7 18:41:47

告别Keil依赖:手把手教你用VSCode+arm-none-eabi-gcc搭建开源嵌入式开发环境

告别Keil依赖&#xff1a;手把手教你用VSCodearm-none-eabi-gcc搭建开源嵌入式开发环境 嵌入式开发领域长期被商业IDE垄断的时代正在终结。随着开源工具的成熟&#xff0c;越来越多的开发者开始追求更自由、更灵活的解决方案。本文将带你从零开始&#xff0c;在VSCode中搭建一套…

作者头像 李华
网站建设 2026/7/7 18:44:06

2024年IntelliJ IDEA必备插件清单:从Mybatis跳转到彩虹括号的实战配置

2024年IntelliJ IDEA高效开发插件全攻略&#xff1a;从Mybatis到代码美化 在Java开发领域&#xff0c;IntelliJ IDEA无疑是众多开发者的首选IDE。根据2023年开发者生态调查报告显示&#xff0c;超过72%的Java开发者将其作为主力开发工具。但真正让IDEA从优秀走向卓越的&#xf…

作者头像 李华