Vue 动态组件(Dynamic Components)

Vue 动态组件(Dynamic Components)

动态组件是 Vue 中一个非常实用的特性,它允许我们在同一个挂载点(一个 <component> 元素)上动态地切换不同的组件。这种机制使得组件的渲染逻辑更加灵活,尤其在需要根据用户交互或应用状态改变视图时非常有用。

什么是动态组件

简单来说,动态组件就是通过一个特殊的 <component> 元素,并绑定其 is 属性来决定当前要渲染的组件is 属性的值可以是一个已注册的组件名,也可以是一个导入的组件对象。

is 的值发生变化时,Vue 就会销毁旧的组件实例并用新的组件替换。

基本用法

使用 <component> 元素

在模板中,使用 <component> 标签,并通过 :is 绑定要渲染的组件:

vue 复制代码
<template>
  <component :is="currentComponent"></component>
</template>
​
<script setup>
import { ref } from 'vue'
import ComponentA from './ComponentA.vue'
import ComponentB from './ComponentB.vue'
​
const currentComponent = ref(ComponentA) // 也可以使用组件名 'ComponentA'
</script>

:is 的两种绑定方式

  • 绑定组件对象(推荐):直接导入组件并绑定。

    vue 复制代码
    <script setup>
    import { ref } from 'vue'
    import ComponentA from './ComponentA.vue'
    import ComponentB from './ComponentB.vue'
    ​
    const currentComponent = ref(ComponentA) // 也可以使用组件名 'ComponentA'
    </script>
  • 绑定组件名称字符串 :组件必须在 components 选项中注册(选项式API)或全局注册。

    vue 复制代码
    <script>
    // 选项式 API 示例
    export default {
      data() {
        return {
          current: 'MyComponent'
        }
      },
      components: {
        MyComponent
      }
    }
    </script>

实际示例:通过按钮切换组件

vue 复制代码
<template>
  <div>
    <button
      v-for="tab in tabs"
      :key="tab"
      @click="currentTab = tab"
      :class="{ active: currentTab === tab }"
    >
      {{ tab }}
    </button>
​
    <component :is="currentTabComponent" class="tab-content"></component>
  </div>
</template>
​
<script setup>
import { ref, computed } from 'vue'
import HomeTab from './HomeTab.vue'
import PostsTab from './PostsTab.vue'
import ArchiveTab from './ArchiveTab.vue'
​
const tabs = ['Home', 'Posts', 'Archive']
const currentTab = ref('Home')
​
const currentTabComponent = computed(() => {
  switch (currentTab.value) {
    case 'Home': return HomeTab
    case 'Posts': return PostsTab
    case 'Archive': return ArchiveTab
    default: return HomeTab
  }
})
</script>

使用 <keep-alive> 缓存组件状态

默认情况下,每次切换动态组件,Vue 都会销毁旧组件并创建新组件,这意味着组件内部的状态会丢失。如果我们希望保留组件的状态(例如表单输入内容、滚动位置等),可以将 <component> 包裹在 <keep-alive> 标签内。

vue 复制代码
<template>
  <keep-alive>
    <component :is="currentTabComponent"></component>
  </keep-alive>
</template>

这样,被切换掉的组件会被缓存,而不是销毁。当再次切换回来时,组件会从缓存中恢复,保留之前的状态。

按条件缓存

<keep-alive> 还支持 includeexclude 属性,用于指定哪些组件需要被缓存(通过组件名称匹配)。

vue 复制代码
<keep-alive include="HomeTab,PostsTab">
  <component :is="currentTabComponent"></component>
</keep-alive>

动态组件与异步组件结合

当应用较大时,我们可以结合 Vue 的异步组件来按需加载,提高首屏加载速度。

vue 复制代码
<template>
  <component :is="asyncComponent"></component>
</template>
​
<script setup>
import { ref, defineAsyncComponent } from 'vue'
​
const asyncComponent = ref(null)
​
// 假设在某个时机加载组件
function loadComponent() {
  asyncComponent.value = defineAsyncComponent(() =>
    import('./HeavyComponent.vue')
  )
}
</script>

动态组件的 is 属性可以直接接收一个异步组件工厂函数,Vue 会在需要渲染时自动解析它。

注意事项

is 属性的绑定方式(Vue 2 vs Vue 3)

  • Vue 3 :直接使用 :is="组件对象/名称",无需额外指令。
  • Vue 2 :动态组件的 is 属性通常写作 :is="componentName",但如果想直接传入组件对象,需要使用 is 属性并配合 v-bind

避免使用 HTML 元素名作为组件名

在 Vue 3 中,如果将 is 绑定到一个 HTML 标签名(如 'div'),Vue 会将其渲染为普通 HTML 元素,而不是 Vue 组件。这通常用于在原生元素上动态切换标签,但如果你想要的是 Vue 组件,请确保绑定的值是组件对象或已注册的组件名称。

XSS 防范

永远不要将用户可编辑的内容直接作为 is 的值(例如通过 v-html 或拼接字符串),否则可能导致 XSS 攻击。应当始终使用受控的组件名或组件对象。

v-if / v-else 的选择

  • 如果只有少数几个固定组件的切换,使用 v-if / v-else-if / v-else 也可以。
  • 当组件的数量不确定或需要动态变化时,动态组件更加简洁。
相关推荐
怕浪猫1 小时前
FDE 如何正确解决现场项目工程性的问题
前端·后端·ai编程
西瓜太郎12341 小时前
外层模型卡片与分组详情成功率不一致,应该怎么排查?
前端·typescript·go·软件工程·react
GreenTea1 小时前
vLLM 与 SGLang KV Cache 底层实现机制深度调研报告
前端·后端·算法
毕业设计7034 小时前
(免费领源码) 基于微信小程序的预制菜商城的设计与实现25172-java、PHP、python、C#、小程序、大数据、单片机、网络工程等)
vue.js·python·mysql·微信小程序·pycharm·微信开发者工具·推荐算法
xifangge20254 小时前
AGENTS.md 怎么写?涵盖 Java、Python、Vue、Go 的 8 套开箱即用模板
java·vue.js·python
几何心凉4 小时前
没有万能模型:我用 AiiOnly Token Plan,把多款大模型的长处拼进同一个项目
前端
kyriewen4 小时前
Claude Code 的额度今天缩水了17%——官方公告上写的是"永久提高25%"
前端·ai编程·claude
雪芽蓝域zzs5 小时前
vue解构平铺VS对象包裹
前端·javascript·vue.js
风骏时光牛马6 小时前
从零到实战,完整AI学习路线
前端
三十而立洋6 小时前
深入理解 Monorepo:子包安装依赖
前端·前端工程化