Skip to content

动态组件

有些场景会需要在两个组件间来回切换,比如 Tab 界面:

vue
<script setup>
import Home from "./Home.vue";
import Posts from "./Posts.vue";
import Archive from "./Archive.vue";
import { ref } from "vue";

const currentTab = ref("Home");

const tabs = {
  Home,
  Posts,
  Archive,
};
</script>

<template>
  <div class="demo">
    <button
      v-for="(_, tab) in tabs"
      :key="tab"
      :class="['tab-button', { active: currentTab === tab }]"
      @click="currentTab = tab"
    >
      {{ tab }}
    </button>
    <component :is="tabs[currentTab]" class="tab"></component>
  </div>
</template>

<style>
.demo {
  font-family: sans-serif;
  border: 1px solid #eee;
  border-radius: 2px;
  padding: 20px 30px;
  margin-top: 1em;
  margin-bottom: 40px;
  user-select: none;
  overflow-x: auto;
}

.tab-button {
  padding: 6px 10px;
  border-top-left-radius: 3px;
  border-top-right-radius: 3px;
  border: 1px solid #ccc;
  cursor: pointer;
  background: #f0f0f0;
  margin-bottom: -1px;
  margin-right: -1px;
}

.tab-button:hover {
  background: #e0e0e0;
}

.tab-button.active {
  background: #e0e0e0;
}

.tab {
  border: 1px solid #ccc;
  padding: 10px;
}
</style>
vue
<template>
  <div class="tab">Home component</div>
</template>
vue
<template>
  <div class="tab">Posts component</div>
</template>
vue
<template>
  <div class="tab">Posts component</div>
</template>

在演练场中查看示例

上面的例子是通过 Vue 的 <component> 元素和特殊的 is attribute 实现的:

vue
<!-- currentTab 改变时组件也改变 -->
<component :is="tabs[currentTab]"></component>

在上面的例子中,被传给 :is 的值可以是以下几种:

  • 被注册的组件名
  • 导入的组件对象

你也可以使用 is attribute 来创建一般的 HTML 元素。

当使用 <component :is="..."> 来在多个组件间作切换时,被切换掉的组件会被卸载。我们可以通过 <KeepAlive> 组件 强制被切换掉的组件仍然保持“存活”的状态。

案例

需求:完成一个注册功能页面,2 个按钮切换,一个填写注册信息,一个填写用户简介信息

效果如下:

动态组件

  1. 准备被切换的 - UserName.vue / UserInfo.vue 2 个组件

  2. 引入到 UseDynamic.vue 注册

  3. 准备变量来承载要显示的"组件名"

  4. 设置挂载点 <component>, 使用 is 属性来设置要显示哪个组件

  5. 点击按钮 – 修改 comName 变量里的"组件名"

vue
<script setup>
// 目标:动态组件 - 切换组件显示
// 场景:同一个挂载点要切换 不同组件 显示
// 1. 创建要被切换的组件 - 标签 + 样式
// 2. 引入到要展示的 vue 文件内,注册
// 3. 变量 - 承载要显示的组件名
// 4. 设置挂载点<component :is="变量"></component>
// 5. 点击按钮 - 切换 comName 的值为要显示的组件名

import UserName from "./components/UserName.vue";
import UserInfo from "./components/UserInfo.vue";
import { ref } from "vue";

const com = ref(UserName);
</script>

<template>
  <div>
    <button @click="com = UserName">账号密码填写</button>
    <button @click="com = UserInfo">个人信息填写</button>

    <p>下面显示注册组件 - 动态切换:</p>
    <div style="border: 1px solid red;">
      <component :is="com"></component>
    </div>
  </div>
</template>

<style scoped></style>

总结:vue 内置 component 组件,配合 is 属性,设置要显示的组件名字

组件缓存

组件切换会导致组件被频繁销毁和重新创建,性能不高。使用 Vue 内置的 keep-alive 组件,可以让包裹的组件保存在内存中不被销毁

演示 1: 可以先给 UserName.vue 和 UserInfo.vue 注册 created 和 destroyed 生命周期事件,观察创建和销毁过程

演示 2: 使用 keep-alive 内置的 vue 组件,让动态组件缓存而不是销毁

语法:

Vue 内置的 keep-alive 组件 包起来要频繁切换的组件

vue
<template>
  <div style="border: 1px solid red;">
    <!-- Vue 内置 keep-alive 组件,把包起来的组件缓存起来 -->
    <keep-alive>
      <component :is="com"></component>
    </keep-alive>
  </div>
</template>

补充生命周期:

  • activated - 激活
  • deactivated - 失去激活状态

总结:keep-alive 可以提高组件的性能,内部包裹的标签不会被销毁和重新创建,触发激活和非激活的生命周期方法

激活和非激活

目标:被缓存的组件不再创建和销毁,而是激活和非激活

补充 2 个钩子方法名:

onActivated – 激活时触发

onDeactivated – 失去激活状态触发