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

先搞懂Keep Alive和include是干啥的

terry 1天前 阅读数 14 #Vue
文章标签 Keep Alive;include

p>咱做Vue2项目时,肯定碰到过组件切换后状态丢了的情况,比如表单页切出去再回来,输入的内容没了;列表页切到详情再返回,滚动位置重置了,这时候Keep - Alive就能解决缓存问题,但光用Keep - Alive还不够“细”,得靠include精准控制哪些组件该缓存,今天就把Vue2里Keep - Alive的include从用法、场景到踩坑,一次性讲明白,新手也能看懂~

Vue里的Keep - Alive是内置抽象组件,它的核心作用是“缓存组件实例”——当包裹动态组件时,不活动的组件不会被销毁,而是暂存起来;下次再渲染时,直接拿缓存的实例用,不用重新创建、销毁,既能提升性能,又能保留组件状态(比如表单输入、滚动位置)。

但要是所有组件都无脑缓存,内存容易“爆炸”(比如几十上百个组件都存着实例),这时候include就成了“筛子”——它能指定“只有哪些组件”能进缓存池,其他组件该销毁就销毁,既保留必要状态,又控住内存。

举个实际例子:做导航栏时有“首页”“订单”“我的”三个组件,首页内容简单,切换时重新加载没负担;但订单页有复杂筛选条件,我的页面有表单,这俩切换时得保留状态,这时候用 <keep - alive include="Order,My"> 包裹动态组件,只有name为Order、My的组件会被缓存,首页不缓存,精准又高效。

这里必须强调组件的name选项!因为include匹配的是组件的name属性,比如Order组件得这么写:

export default {
  name: 'Order', // 必须和include里的名字完全一致
  // ...其他逻辑
}

单文件组件(比如Order.vue)如果没显式写name,默认name是文件名(Order.vue→name为Order),但为了避免混淆(比如文件名和实际需求名不一致),最好显式声明name

include的三种使用格式咋玩?

include支持字符串、正则、数组三种格式,每种格式用法不同,得注意绑定方式和场景适配。

字符串格式(最基础,适合固定场景)

直接写组件name,多个用逗号分隔。

<keep-alive include="Order,My">
  <component :is="currentComponent"></component>
</keep-alive>

这种写法适合“缓存列表固定不变”的场景,比如后台管理系统里,始终只缓存订单、个人中心这类核心组件,但如果需要动态调整缓存列表(比如根据用户权限加/减缓存),字符串格式就不够灵活了。

正则格式(要结合v - bind,适合批量匹配)

正则得用v - bind绑定,用来“批量匹配”组件name,比如想缓存所有name以Page结尾的组件:

<keep-alive :include="/Page$/">
  <component :is="currentComponent"></component>
</keep-alive>

这时,只要组件name是OrderPageMyPage这类,就会被匹配到,但正则用的时候要谨慎——别写太宽泛(比如匹配所有),否则缓存范围失控,内存又该“爆炸”了。

数组格式(动态场景首选,灵活可控)

数组也得用v - bind绑定,适合动态增减缓存组件的情况,比如根据用户操作(打开新标签、切换权限),决定哪些组件该缓存:

<keep-alive :include="cacheComponents">
  <component :is="currentComponent"></component>
</keep-alive>
<script>
export default {
  data() {
    return {
      cacheComponents: ['Order', 'My'] // 初始缓存这俩
    }
  },
  methods: {
    addCache(componentName) {
      this.cacheComponents.push(componentName) // 动态添加新组件到缓存列表
    }
  }
}
</script>

数组里的每个元素对应组件的name,通过修改数组就能灵活控制缓存范围,比如做多标签页时,用户打开新标签,就把该标签组件的namepush进数组,实现“打开即缓存”。

实战中啥场景适合用include?

光懂用法不够,得知道啥时候用才“香”,分享几个真实开发场景,看完就知道include的价值在哪:

多Tab切换(后台管理系统高频需求)

后台系统里,用户会打开多个标签页(比如订单详情、客户信息、报表),如果切换标签时,每个页面都重新加载,不仅慢,表单内容、筛选条件还会丢,这时候用include指定这些Tab对应的组件,让它们保持缓存,体验直接起飞。

举个简化版代码(结合路由+多标签):

<keep-alive :include="activeTabNames">
  <component 
    v-for="tab in openTabs" 
    :key="tab.name" 
    :is="tab.component"
  ></component>
</keep-alive>
<script>
export default {
  data() {
    return {
      openTabs: [], // 已打开的标签页列表
      activeTabNames: [] // 要缓存的组件name数组
    }
  },
  watch: {
    openTabs(newTabs) {
      // 每次打开新标签,把组件name同步到缓存列表
      this.activeTabNames = newTabs.map(tab => tab.name)
    }
  }
}
</script>

用户切换Tab时,已打开的页面状态(比如表单输入、表格筛选)都能保留,不用重复操作,效率和体验都拉满。

表单页来回切换(比如个人信息编辑)

用户填个人信息时,有很多输入框(姓名、电话、地址…),切到其他页面再回来,要是内容没了,体验贼差,这时候给表单组件加缓存,完美解决问题:

<keep-alive include="ProfileForm">
  <router-view></router-view>
</keep-alive>

ProfileForm组件里显式声明name: 'ProfileForm',这样路由切换到其他页面再回来,表单数据稳稳保留,用户不用重新输入。

列表+详情页(保留列表状态)

比如商品列表页,用户下滑浏览很多商品,点进详情页后返回,列表得回到之前的滚动位置和筛选状态,这时候给列表组件用include缓存,丝滑无比:

<keep-alive include="GoodsList">
  <router-view></router-view>
</keep-alive>

GoodsList组件缓存后,离开再回来时,数据、滚动条位置、筛选条件都能保留,不用重新请求接口、重新渲染,性能和体验双提升。

用include时容易踩的坑有哪些?

踩过坑才知道避坑技巧,这几个常见问题得重点关注:

组件name没写对,匹配不上

很多同学栽在这:组件里没写name,或者name和include里的字符串不一致,导致缓存失效,比如组件定义是这样:

export default {
  // 没写name,默认name是组件文件名(比如GoodsList.vue→name为GoodsList)
  // 但如果用了vue - loader的命名转换,或文件名和需求名不一致,就会匹配失败
}

解决方法:每个要被include的组件,都显式声明name,保证和include里的字符串完全一致。

export default {
  name: 'GoodsList', // 和include里的"GoodsList"严格对应
  // ...其他逻辑
}

动态修改include不生效

想根据用户操作(比如点击按钮添加缓存)动态修改include,但直接改数组/字符串没反应,这是因为Keep - Alive在初始化时就确定了缓存规则,动态修改需要让Vue“感知到变化”。

解决方法:用计算属性watch处理,比如用计算属性动态返回缓存列表:

<keep-alive :include="computedCache">
  <component :is="currentComponent"></component>
</keep-alive>
<script>
export default {
  data() {
    return {
      needCache: ['Order'],
      user: { isVIP: false }
    }
  },
  computed: {
    computedCache() {
      // 根据用户权限动态调整缓存列表
      if (this.user.isVIP) {
        return [...this.needCache, 'VIPPage'] // VIP用户额外缓存VIPPage
      }
      return this.needCache
    }
  }
}
</script>

这样computedCache变化时,Keep - Alive会重新计算缓存范围,动态修改就生效了。

缓存太多,页面变卡

如果include包含几十个组件,每个组件都缓存实例,内存会被占满,页面轻则卡顿,重则崩溃。

解决方法:只缓存必要组件(比如列表页缓存,详情页不缓存,因为详情页数据每次可能不同,缓存意义不大);或者用Keep - Alive的max属性限制缓存数量——超过数量后,会淘汰最久未使用的组件实例。

举个max的用法:

<keep-alive include="Order,My" max="5">
  <component :is="currentComponent"></component>
</keep-alive>

这样最多缓存5个组件实例,避免内存“爆炸”。

include背后的原理是啥?(想深入的同学看)

了解原理能更“自信”地用include,Vue2中,Keep - Alive是个抽象组件,核心逻辑围绕两个关键对象展开:

  • cache:对象结构,存组件实例,键是组件的name(或内部标识cid)。
  • keys:数组结构,存缓存的键,用来处理max淘汰策略(比如LRU算法,淘汰最久未使用的实例)。

当组件被Keep - Alive包裹时,渲染流程会走特殊逻辑:

  1. 先判断组件的name是否在include允许的范围内(exclude是“排除”,include是“包含”)。
  2. 如果匹配,就从cache里取实例;没有的话,创建新实例并存入cache
  3. 组件切换时,不销毁实例,只是隐藏,所以状态能保留。

比如include是数组['Order'],只有nameOrder的组件会被检查是否缓存,原理不用深究,但知道这个逻辑后,遇到“某个组件没被缓存”的问题,第一时间排查name是否匹配,效率翻倍~

p>Vue2的Keep - Alive include是个控制组件缓存范围的“利器”,用好了能大幅提升页面性能和用户体验,记住这几点:组件name要写对、根据场景选格式(字符串/正则/数组)、避坑name不匹配和动态修改失效、别过度缓存,下次做Tab切换、表单保持、列表回滚这些需求时,就知道怎么用include精准控制缓存啦~要是还有疑问,评论区聊~

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

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

热门