Vue Router里keep alive的exclude怎么用?要注意哪些细节?
做Vue项目时,用keep - alive缓存组件能减少重复渲染、提升性能,但总有一些页面(比如详情页、登录页)不想缓存,这时候就得靠exclude属性,可exclude咋用才对?用的时候容易踩哪些坑?今天把Vue Router里keep - alive的exclude从基础到实战拆清楚,解决你开发里的疑惑。
keep - alive的exclude是干啥的?
先回忆下keep - alive的作用:它是Vue内置组件,能缓存组件实例,让组件切换时不销毁、不重新创建,保留数据和状态(比如表单输入、滚动位置),但有些页面每次进入都要“刷新”,比如商品详情页(每次看不同商品,数据要最新)、登录页(退出后再进要清空输入框),这时候就需要排除缓存——这就是exclude的核心作用。
简单说,exclude是keep - alive的属性,用来指定哪些组件不缓存,被exclude匹配到的组件,每次进入都会重新创建(执行created、mounted等生命周期),离开时销毁,状态不保留。
exclude支持哪些传值格式?怎么用?
exclude能接收字符串、正则、数组三种格式,但传值时要注意语法细节,否则容易失效。
字符串格式:多组件名用逗号分隔
如果只有少数组件要排除,用字符串最直观,比如要排除“DetailPage”和“LoginPage”两个组件,写法是:
<keep-alive exclude="DetailPage,LoginPage"> <router-view></router-view> </keep-alive>
⚠️ 注意:这里的“DetailPage”“LoginPage”必须和组件的name
选项完全一致(包括大小写、单词拼写)。
正则表达式:配合v - bind使用
想用正则匹配一批组件?得用v - bind
(简写)绑定,因为HTML属性里不能直接写正则,比如要排除所有名字带“Detail”或“Login”的组件:
<keep-alive :exclude="/Detail|Login/"> <router-view></router-view> </keep-alive>
⚠️ 正则匹配的是组件的name
,所以组件名要符合正则规则,比如组件name是“OrderDetail”,会被/Detail/
匹配到。
数组格式:动态控制更灵活
如果排除的组件需要“动态变化”(比如登录后不排除个人中心,未登录时排除),用数组+v - bind
最方便,写法:
<keep-alive :exclude="['DetailPage', 'LoginPage']"> <router-view></router-view> </keep-alive>
数组里的每一项是组件name
的字符串,也可以用计算属性动态生成数组,
<template> <keep-alive :exclude="excludeComponents"> <router-view></router-view> </keep-alive> </template> <script> export default { computed: { excludeComponents() { // 根据用户登录状态动态决定排除哪些组件 return this.$store.state.user.isLogin ? [] : ['UserPage']; } } } </script>
项目里用exclude要注意哪些细节?
很多同学明明写了exclude,却发现缓存没生效,大概率是踩了这些“隐藏规则”。
组件必须显式声明name
exclude匹配的是组件的name
选项,所以组件一定要显式写name!比如单文件组件:
<template>...</template> <script> export default { name: 'DetailPage', // 必须写,否则exclude匹配不到 // ... } </script>
如果没写name
,Vue会默认取“文件名”(比如DetailPage.vue的name是DetailPage),但如果是通过import()
引入的异步组件,或用了第三方组件库,name
可能异常,所以自己写的组件一定要显式声明name。
keep - alive的“包裹范围”要正确
exclude作用的组件必须在keep - alive的直接子组件范围内。
<keep-alive exclude="DetailPage"> <!-- DetailPage必须是router-view渲染的组件,且在keep-alive内部 --> <router-view></router-view> </keep-alive>
如果DetailPage是在keep - alive外面渲染的(比如用v - if
把它包在外面),exclude对它完全没效果。
结合路由meta统一管理(进阶技巧)
大型项目里,哪些页面要排除缓存,适合用路由元信息(meta)统一配置,比如在路由里加meta: { noCache: true }
:
const routes = [ { path: '/detail', component: Detail, meta: { noCache: true } // 标记为不缓存 }, { path: '/home', component: Home, meta: { noCache: false } // 需要缓存 } ]
然后在App.vue里动态生成exclude数组:
<template> <keep-alive :exclude="excludeArr"> <router-view></router-view> </keep-alive> </template> <script> export default { computed: { excludeArr() { // 筛选出所有meta.noCache为true的路由,取它们的组件name return this.$router.options.routes .filter(route => route.meta.noCache) .map(route => route.component.name); } } } </script>
这样一来,所有“是否缓存”的逻辑都集中在路由配置里,后期维护更方便。
exclude和include一起用,谁优先级更高?
项目里可能同时用include
(指定要缓存的组件)和exclude
(指定不缓存的组件),这时候优先级是:exclude更高。
举个例子:
<keep-alive include="HomePage,ListPage" exclude="ListPage"> <router-view></router-view> </keep-alive>
这里ListPage既在include里(理论上要缓存),又在exclude里(要排除),最终ListPage不会被缓存——因为exclude优先级更高。
所以实际开发中,如果同时用这两个属性,要避免逻辑冲突,建议优先用exclude,或者只用其中一个。
exclude没生效?五步排查法
碰到“明明写了exclude,组件还是被缓存”的情况,按这几步查:
检查组件name
是否匹配
打开组件文件,看name
选项和exclude里的字符串是否完全一致(包括大小写、空格),比如组件name是“UserCenter”,exclude里写“usercenter”就会匹配失败。
确认组件在keep - alive范围内
看keep - alive标签是否包裹了目标组件,比如路由组件是通过<router - view>
渲染的,那<router - view>
必须在keep - alive内部:
<!-- 正确:router-view在keep-alive里 --> <keep-alive exclude="DetailPage"> <router-view></router-view> </keep-alive> <!-- 错误:router-view在keep-alive外,exclude无效 --> <router-view></router-view> <keep-alive exclude="DetailPage"></keep-alive>
检查exclude的传值格式
如果用数组或正则,必须加v - bind
(),比如写成<keep - alive exclude="['a','b']">
,此时exclude的值是字符串“['a','b']”,而不是数组,导致匹配失败,正确写法是<keep - alive :exclude="['a','b']">
。
异步组件的name
是否正常
如果组件是用import()
异步加载的,要确保组件内部显式声明了name,因为异步组件加载前,name可能是undefined
或默认值,导致exclude匹配不到。
浏览器调试:看组件生命周期
怀疑组件被缓存时,打开浏览器控制台,看组件的created
、mounted
钩子是否只执行一次(被缓存)或每次进入都执行(未被缓存),如果每次进入都执行,说明exclude生效;如果只执行一次,说明没生效,回到前几步排查。
实战:用exclude优化电商项目页面性能
以“电商APP”为例,页面有:首页(Home)、商品列表(List)、商品详情(Detail)、购物车(Cart)、个人中心(User),需求是:Home、List、Cart、User需要缓存(保留滚动位置、表单状态),Detail不需要缓存(每次进入刷新商品数据)。
步骤1:给组件加name
每个组件显式声明name
:
<!-- Home.vue --> <script> export default { name: 'HomePage', // ... } </script> <!-- List.vue --> <script> export default { name: 'ListPage', // ... } </script> <!-- Detail.vue --> <script> export default { name: 'DetailPage', // ... } </script> <!-- Cart.vue --> <script> export default { name: 'CartPage', // ... } </script> <!-- User.vue --> <script> export default { name: 'UserPage', // ... } </script>
步骤2:在App.vue里配置keep - alive + exclude
把DetailPage排除在缓存外:
<template> <div id="app"> <keep-alive exclude="DetailPage"> <router-view></router-view> </keep-alive> </div> </template>
步骤3:复杂场景扩展(比如User页面动态缓存)
如果User页面“未登录时不缓存,登录后缓存”,用计算属性动态控制exclude:
<template> <div id="app"> <keep-alive :exclude="excludeComponents"> <router-view></router-view> </keep-alive> </div> </template> <script> export default { computed: { excludeComponents() { // 从Vuex取登录状态 const isLogin = this.$store.state.user.isLogin; // 未登录时排除UserPage,登录后不排除 return isLogin ? [] : ['UserPage']; } } } </script>
这样配置后,Home、List、Cart在切换时状态保留,Detail每次进入重新加载,User页面根据登录状态动态控制缓存,性能和用户体验都能兼顾。
keep - alive的exclude是“精准控制组件缓存”的利器,但要用好得注意组件name的匹配、传值格式、包裹范围这些细节,记住核心逻辑:exclude优先级高、组件name要准确、动态场景用数组或计算属性,下次碰到页面缓存控制的需求,按这篇的思路拆解,就能少踩坑、效率翻倍~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。