Code前端首页关于Code前端联系我们

Vue Router里keep alive的exclude怎么用?要注意哪些细节?

terry 3小时前 阅读数 7 #Vue
文章标签 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匹配不到。

浏览器调试:看组件生命周期

怀疑组件被缓存时,打开浏览器控制台,看组件的createdmounted钩子是否只执行一次(被缓存)或每次进入都执行(未被缓存),如果每次进入都执行,说明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前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门