以观书法
108.85M · 2026-02-05
在Vue开发中,我们经常遇到「组件动态切换」的需求——比如标签页(Tabs)、步骤条、弹窗内容切换、路由页面缓存等。直接用v-if/v-else切换组件,会频繁销毁和重建组件,不仅性能损耗大,还会丢失组件内部状态(比如输入框内容、滚动位置)。
而 <component :is> 是Vue内置的动态组件语法,专门用于实现组件灵活切换;搭配 keep-alive 内置组件,可缓存切换后的组件实例,避免重复渲染、保留组件状态。这对组合是Vue性能优化的高频手段,也是面试必问的实操知识点。
核心价值:切换组件不销毁、不重建 → 提升页面性能;保留组件状态 → 优化用户体验,两者配合堪称“动态切换天花板”。
在学习组合用法前,先快速掌握和keep-alive的基础用法,避免混淆核心逻辑,新手也能轻松跟上。
核心作用:通过:is绑定的值,动态渲染不同的组件,值可以是「组件名」「组件配置对象」或「异步组件」,灵活适配各类切换场景。
最简实操(Vue3 <script setup> 写法,首选):
<template>
<!-- 核心::is绑定要渲染的组件名 -->
<component :is="currentComponent" />
<!-- 切换按钮,修改currentComponent的值 -->
<button @click="currentComponent = 'ComponentA'">显示组件A</button>
<button @click="currentComponent = 'ComponentB'">显示组件B</button>
</template>
<script setup>
// 1. 导入需要切换的组件
import ComponentA from './ComponentA.vue'
import ComponentB from './ComponentB.vue'
// 2. 绑定动态组件的变量(初始渲染ComponentA)
const currentComponent = ref('ComponentA')
</script>
关键注意点:
核心作用:缓存包裹在其内部的组件实例,避免组件被频繁销毁和重建,仅在第一次渲染时初始化,切换后保留组件原有状态。
最简实操(单独使用,仅缓存单个组件):
<template>
<!-- 包裹需要缓存的组件,组件切换后不会被销毁 -->
<keep-alive>
<ComponentA />
</keep-alive>
</template>
核心属性(重点,组合用法必用):
<component :is> + keep-alive 组合用法(重点!)这是实际开发中最常用的写法,结合两者优势:用实现动态切换,用keep-alive缓存切换后的组件,保留状态+提升性能,以「标签页Tabs」为经典案例,代码可直接复制套用。
需求:3个标签页,切换时保留每个标签页内部的状态(比如输入框内容),不重复渲染组件。
<template>
<div class="tabs-container">
<!-- 标签切换按钮 -->
<div class="tabs-header">
<button
v-for="tab in tabs"
:key="tab.name"
@click="currentTab = tab.name"
:class="{ active: currentTab === tab.name }"
>
{{ tab.label }}
</button>
</div>
<!-- 核心组合:keep-alive缓存 + component:is动态切换 -->
<keep-alive
include="Tab1,Tab2,Tab3" // 仅缓存这3个组件(匹配组件name)
max="3" // 最大缓存3个实例(避免内存泄漏)
>
<component :is="currentTab" />
</keep-alive>
</div>
</template>
<script setup>
import { ref } from 'vue'
// 导入3个标签页组件
import Tab1 from './Tab1.vue'
import Tab2 from './Tab2.vue'
import Tab3 from './Tab3.vue'
// 标签页配置(关联组件名和显示文本)
const tabs = ref([
{ name: 'Tab1', label: '标签1' },
{ name: 'Tab2', label: '标签2' },
{ name: 'Tab3', label: '标签3' }
])
// 当前激活的标签页(绑定动态组件)
const currentTab = ref('Tab1')
</script>
注意:keep-alive的include/exclude属性,需要匹配组件的name属性才能生效,否则缓存失败,以Tab1.vue为例:
<template>
<div class="tab1">
<h3>标签1内容</h3>
<!-- 输入框:切换标签后,输入的内容会被保留(缓存生效) -->
<input v-model="inputVal" placeholder="请输入内容" />
</div>
</template>
<script setup>
import { ref } from 'vue'
// 关键:定义name属性,与keep-alive的include匹配
defineOptions({
name: 'Tab1' // 必须和include中的值一致(区分大小写)
})
const inputVal = ref('')
</script>
提示:Tab2、Tab3组件配置和Tab1一致,仅需修改name属性(Tab2、Tab3)和内部内容即可。
常见原因及解决方案:
场景:动态切换的组件数量较多(如10+个),长期缓存会占用过多内存,导致页面卡顿。
解决方案:给keep-alive添加max属性,限制缓存的最大实例数(如max="5"),超出后会自动销毁最早缓存的组件。
解决方案:结合include和exclude属性,精准控制缓存范围,示例:
<!-- 缓存Tab1、Tab2,排除Tab3 -->
<keep-alive include="Tab1,Tab2" exclude="Tab3">
<component :is="currentTab" />
</keep-alive>
现象:组件被缓存后,切换时不会触发created、mounted等生命周期钩子(因为组件未被销毁和重建)。
解决方案:使用Vue提供的缓存生命周期钩子,替代传统生命周期:
<script setup>
defineOptions({ name: 'Tab1' })
// 组件被激活时触发(切换到该标签页)
onActivated(() => {
console.log('Tab1被激活,可执行刷新数据等操作')
})
// 组件被停用时触发(切换到其他标签页)
onDeactivated(() => {
console.log('Tab1被停用,可执行清理操作')
})
</script>
除了标签页,这对组合还能适配以下高频开发场景,核心逻辑完全一致,只需灵活调整配置:
步骤条的每一步对应一个组件,切换步骤时保留当前步骤的输入内容、选择状态,避免用户重复操作,提升体验。
弹窗内需要切换不同的表单、详情内容,搭配keep-alive可保留表单输入状态,避免弹窗关闭/切换时丢失内容。
在路由视图中使用组合写法,缓存指定路由页面,切换路由时保留页面滚动位置、输入状态(如列表页分页、搜索框内容):
<keep-alive include="Home,List">
<router-view /> <!-- 路由视图本质也是动态组件 -->
</keep-alive>
其实+keep-alive的用法并不复杂,核心就是“切换”和“缓存”两个关键词。掌握本文的实操案例和避坑点,就能轻松应对各类动态切换场景,既提升页面性能,又优化用户体验,面试时也能从容应对~