插槽内容无法被直接缓存,必须将需保留状态的逻辑封装为具名组件,再用包裹该组件而非;作用域插槽可用于父子通信。

Vue.js 中使用 <slot></slot> 传递内容时,插槽本身不参与组件实例的生命周期管理,因此默认不会被 <keep-alive></keep-alive> 缓存。若想实现“插槽内容的状态缓存”,关键不是缓存 slot 本身(它只是渲染片段),而是缓存承载插槽的子组件实例,并确保其内部状态(如表单输入、滚动位置、展开折叠状态等)在切换后保持不变。
理解 Slots 与 Keep-alive 的作用边界
<slot></slot> 是内容分发机制,本质是父组件向子组件“注入 DOM 片段”,它没有独立的实例、data 或生命周期;而 <keep-alive></keep-alive> 缓存的是**有状态的组件实例**(即被包裹的 `
典型场景:带 Tab 切换的可缓存表单页
例如一个用户资料编辑页,包含「基本信息」「账户安全」「通知设置」三个 tab,每个 tab 是独立组件,且需保留各自输入状态:
- 父组件(TabLayout)用 `
` 渲染当前激活的 tab 内容 - 但实际被 `
` 包裹的,是每个 tab 对应的子组件(如 `UserInfoForm`、`SecurityForm`) - 通过 `v-if` 或动态组件 + `:is` 配合 `keep-alive` 的 `include` 控制哪些组件实例要缓存
示例代码结构:
<!-- TabLayout.vue -->
<template><div class="tab-layout">
<nav class="tabs"><button>基本信息</button>
<button>账户安全</button>
</nav><main class="tab-content"><keep-alive :include="cachedTabs"><component :is="currentTabComponent"></component></keep-alive></main>
</div>
</template><p><script>
export default {
data() {
return {
activeTab: 'user',
cachedTabs: ['UserInfoForm', 'SecurityForm'] // 组件 name
}
},
computed: {
currentTabComponent() {
const map = {
user: () => import('./UserInfoForm.vue'),
security: () => import('./SecurityForm.vue')
}
return map[this.activeTab]
}
}
}
</script></p>
配合作用域插槽实现灵活内容注入
当父组件需向被缓存的子组件传递数据或方法(如保存按钮回调),可用作用域插槽作为桥梁:

