Vue 中的 keep-alive 组件

keep-alive 是 Vue 内置的一个抽象组件,用于缓存不活动的组件实例,而不是销毁它们。这可以保留组件状态或避免重新渲染,从而提升性能。
核心特性
- 组件状态保持 :当组件在
<keep-alive>中切换时,其状态会被保留 - 避免重复渲染:缓存的组件不会重新创建,减少 DOM 操作
- 生命周期变化:添加了特殊的生命周期钩子
基本用法
vue
<template>
<div>
<button @click="currentTab = 'TabA'">Tab A</button>
<button @click="currentTab = 'TabB'">Tab B</button>
<keep-alive>
<component :is="currentTab"></component>
</keep-alive>
</div>
</template>
<script>
export default {
data() {
return {
currentTab: 'TabA'
}
},
components: {
TabA: {
template: '<div>Tab A Content <input placeholder="输入会被保留" /></div>'
},
TabB: {
template: '<div>Tab B Content</div>'
}
}
}
</script>
配置属性
1. include - 指定缓存组件
vue
<!-- 字符串(逗号分隔) -->
<keep-alive include="ComponentA,ComponentB">
<component :is="currentComponent"></component>
</keep-alive>
<!-- 正则表达式 -->
<keep-alive :include="/ComponentA|ComponentB/">
<component :is="currentComponent"></component>
</keep-alive>
<!-- 数组 -->
<keep-alive :include="['ComponentA', 'ComponentB']">
<component :is="currentComponent"></component>
</keep-alive>
2. exclude - 排除不缓存组件
vue
<keep-alive exclude="ComponentC">
<component :is="currentComponent"></component>
</keep-alive>
3. max - 最大缓存实例数(Vue 2.5.0+)
vue
<keep-alive :max="10">
<component :is="currentComponent"></component>
</keep-alive>
生命周期钩子
被 <keep-alive> 包裹的组件会获得两个额外的生命周期钩子:
activated
- 组件被激活时调用
- 当组件第一次渲染和每次从缓存中重新激活时都会触发
deactivated
- 组件被停用时调用
- 当组件被缓存时触发
vue
<script>
export default {
name: 'MyComponent',
activated() {
console.log('组件被激活,恢复状态')
// 例如:重新开始定时器
this.startTimer()
},
deactivated() {
console.log('组件被停用,进入缓存')
// 例如:清除定时器
this.clearTimer()
},
methods: {
startTimer() {
this.timer = setInterval(() => {
console.log('定时器执行')
}, 1000)
},
clearTimer() {
if (this.timer) {
clearInterval(this.timer)
}
}
},
// 传统生命周期依然有效
created() {
console.log('created - 只在第一次创建时调用')
},
mounted() {
console.log('mounted - 只在第一次挂载时调用')
}
}
</script>
与 Vue Router 结合使用
vue
<template>
<div id="app">
<!-- 缓存包含的路由组件 -->
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<!-- 不缓存的路由组件 -->
<router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
</template>
javascript
// router.js
const routes = [
{
path: '/home',
component: Home,
meta: {
keepAlive: true // 需要缓存
}
},
{
path: '/detail/:id',
component: Detail,
meta: {
keepAlive: false // 不需要缓存
}
}
]
高级用法示例
动态决定是否缓存
vue
<template>
<keep-alive :include="cachedComponents">
<router-view></router-view>
</keep-alive>
</template>
<script>
export default {
data() {
return {
cachedComponents: [] // 动态维护需要缓存的组件名
}
},
watch: {
'$route'(to, from) {
// 根据路由规则动态添加/移除缓存
if (to.meta.keepAlive && !this.cachedComponents.includes(to.name)) {
this.cachedComponents.push(to.name)
}
}
}
}
</script>
配合 transition 使用
vue
<transition name="fade" mode="out-in">
<keep-alive>
<component :is="currentComponent"></component>
</keep-alive>
</transition>
实现原理
keep-alive 内部维护一个缓存对象,主要流程:
- 首次渲染时,创建组件实例并缓存
- 组件切换时,将当前组件标记为
deactivated并隐藏 - 再次切回时,从缓存中取出实例,标记为
activated并显示 - 使用 LRU(最近最少使用)算法管理缓存(当使用
max时)
注意事项
- 组件必须有 name 选项 :
include和exclude属性通过组件名匹配 - 避免内存泄漏 :合理设置
max,及时清理不需要的缓存 - 状态一致性 :确保
activated中恢复的状态是正确的 - 异步组件:同样支持,但需要注意加载时机
- 与 v-for 使用:不推荐同时使用,可能会导致缓存混乱
适用场景
- 标签页切换:保持每个标签页的状态
- 表单页面:离开后返回,表单数据不丢失
- 列表页 → 详情页:返回列表页时保持滚动位置和过滤条件
- 需要大量计算或网络请求的组件:避免重复计算/请求
Vue 3 中的变化
在 Vue 3 中,keep-alive 的使用方式类似,但有细微变化:
include和exclude支持组件实例的name或setup函数中的name- 不再支持缓存
<keep-alive>的直接子元素数组
vue
<!-- Vue 3 -->
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" v-if="$route.meta.keepAlive" />
</keep-alive>
<component :is="Component" v-if="!$route.meta.keepAlive" />
</router-view>
keep-alive 是 Vue 中优化组件性能的重要工具,合理使用可以显著提升用户体验,特别是在需要保持组件状态的场景中。