← 返回题目列表

Vue 动态组件 component is 的作用是什么?

中等 第 24 / 27 题 更新于 2026/07/29
Vue动态组件componentkeep-alive

简化版

动态组件通过 <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;简单分支不要强行动态化。