Vue 动态组件 component is 的作用是什么?
简化版
动态组件通过 <component :is="xxx" /> 在同一位置按状态切换不同组件,适合标签页、配置化页面、低代码渲染和步骤表单。它解决的是组件类型动态决定的问题,常与 keep-alive 配合缓存状态。
详细版
动态组件的核心是 is。
<component :is="currentPanel" />
currentPanel 可以是组件对象,也可以是已注册组件名。
当值变化时,Vue 会卸载旧组件并挂载新组件;如果包在 keep-alive 中,符合条件的组件实例可以被缓存。
<keep-alive>
<component :is="activeTab" />
</keep-alive>
面试回答要注意:动态组件不是条件渲染的替代品,而是当“要渲染的组件类型本身是数据”时更合适。
完整版教学
一、动态组件让组件类型变成状态
普通模板里,组件名通常是写死的。
但有些场景组件类型由用户选择、配置文件或路由元信息决定。
此时用大量 v-if 会让模板越来越乱。
<component :is="currentComponent" />
active = 'profile' -> ProfilePanel
active = 'security' -> SecurityPanel
active = 'billing' -> BillingPanel
如果一个设置页有 8 个 tab,用 8 段 v-if 可以实现,但扩展性差。
动态组件把“映射关系”放回数据层,模板只保留一个渲染出口。
二、is 可以接收组件对象或组件名
在 <script setup> 中,更常见的是直接传组件对象。
这样配合 TypeScript 和 import 更清晰,也减少全局注册依赖。
<script setup>
import ProfilePanel from './ProfilePanel.vue'
import SecurityPanel from './SecurityPanel.vue'
const panels = {
profile: ProfilePanel,
security: SecurityPanel
}
</script>
<template>
<component :is="panels[active]" />
</template>
| 写法 | 特点 | 适合场景 |
|---|---|---|
| 组件对象 | 静态可追踪 | 业务组件映射 |
| 注册名字符串 | 依赖注册环境 | 全局组件或兼容老写法 |
| 异步组件 | 可拆包 | 低频大组件 |
如果某个组件有 200 KB 依赖,还可以把它定义成异步组件,再交给动态组件渲染。 这时动态组件和异步组件就形成了“按需决定 + 按需下载”的组合。
三、切换默认会卸载旧组件
没有 keep-alive 时,动态组件切换会销毁旧组件实例。
这意味着组件内部状态会丢失,生命周期也会重新走。
例如在 tab A 输入表单,切到 tab B 再切回来,tab A 可能回到初始状态。
无缓存切换:
Profile mounted -> 切走 unmounted
Security mounted -> 切回 unmounted
Profile 重新 mounted
如果这是预期,例如步骤组件每次都要重置,就没问题。
如果要保留状态,就需要 keep-alive。
这也是动态组件常和 keep-alive 一起出现的原因。
四、keep-alive 可以缓存动态组件实例
keep-alive 会缓存组件实例,而不是每次重新创建。
它适合 tab、列表详情切换、复杂表单暂存等场景。
但缓存不是越多越好,缓存 50 个复杂组件可能占用明显内存。
<keep-alive :include="['ProfilePanel', 'SecurityPanel']" :max="5">
<component :is="panels[active]" />
</keep-alive>
| 配置 | 作用 |
|---|---|
include | 指定哪些组件可缓存 |
exclude | 指定哪些组件不缓存 |
max | 限制缓存实例数量 |
假设每个面板实例平均占 3 MB,缓存 10 个就是 30 MB。 移动端或低配设备上,缓存策略需要控制上限。
五、动态组件适合配置化渲染
低代码、表单设计器、后台工作台常把页面结构存成配置。
配置里写 type: 'input'、type: 'date'、type: 'select',运行时再映射到不同 Vue 组件。
动态组件就是这类系统的基础能力。
<component
:is="widgetMap[item.type]"
v-for="item in schema"
:key="item.id"
v-bind="item.props"
/>
schema -> type -> component -> props -> 渲染
这里必须注意白名单。 不能让后端任意字符串直接决定组件,否则容易出现不可控渲染或安全风险。 通常会维护一个前端组件映射表。
六、不要用动态组件掩盖简单条件
如果只有两个很简单的展示分支,v-if 更直观。
动态组件适合组件类型本身很多、来源动态、需要统一出口的场景。
过度使用会降低可读性,因为读模板时看不到具体渲染了谁。
记忆钩子:v-if 判断显示不显示,component is 判断“这一格到底是谁来演”。
面试回答可以用 tab 和配置化页面举例。
再补上切换会卸载、需要缓存时配 keep-alive,答案就完整了。
七、常见误区与追问
- 误区:动态组件就是 v-if 的高级替代。 简单条件渲染用 v-if 更清楚,动态组件适合组件类型由状态或配置决定。
- 误区:切换动态组件一定会保留内部状态。 默认会卸载旧组件,保留状态需要配合
keep-alive。 - 误区:keep-alive 缓存越多越好。 缓存会占内存,复杂组件要设置 include、exclude 或 max。
- 追问:is 可以传什么? 可以传组件对象,也可以传已注册组件名,还可以结合异步组件。
- 追问:配置化渲染如何避免风险? 用前端白名单映射配置类型到组件,不让外部数据任意指定组件。
- 追问:动态组件的 key 有什么影响? key 会影响复用和重新创建,错误 key 可能导致状态串用或不必要重建。
八、加强记忆
动态组件记成“组件类型数据化”。当同一位置要按 tab、schema 或状态切换不同组件,用 <component :is>;默认切换会卸载,想保留状态加 keep-alive;简单分支不要强行动态化。