Skip to content

动态组件

通过向 <component> 元素传递 is 属性,动态组件实现了组件之间动态切换的能力。

我们通过一个例子来快速了解一下动态组件的工作方式。假设我们有三个独立的组件,它们的标题为 HomeFeedHistory,每个组件的内容是显示它们各自是什么组件。

vue
<!-- Home -->
<template><div class="tab">Home component</div></template>

<!-- Feed -->
<template><div class="tab">Feed component</div></template>

<!-- History -->
<template><div class="tab">History component</div></template>

我们的目标是创建一个可以点击的选项卡界面,根据点击的选项卡动态渲染对应的组件。

当我们在选项卡之间点击时,我们希望不通过路由的方式来动态地挂载和卸载组件。虽然这件事可以借助 v-ifv-else 等条件渲染指令 来实现,但这却是 Vue 动态组件的一个完美的示例。

在父组件 App 中,我们先导入这三个单独的组件,后面会在模板中用到它们。同样我们需要创建一个响应式状态 currentTab,并给它一个初始值 "Home"

vue
<script setup>
  import { ref } from "vue";
  import Home from "./components/Home.vue";
  import Feed from "./components/Feed.vue";
  import History from "./components/History.vue";

  const currentTab = ref("Home");
  const tabs = {
    Home,
    Feed,
    History,
  };
</script>

需要注意的是,tabs 对象中引用的是具体的组件,而不是组件名称。

译注

这里的 tabs 的定义使用了 JavaScript 的属性简写特性。tabs 的 key 是组件名字符串,value 是组件。这样写是为了后面通过 currentTab ,使用组件名来获取组件。

App 组件的模板中,我们会看到渲染了三个单独的选项卡按钮 —— 每个按钮对应一个我们要显示的组件。我们在这里使用了 v-for 指令 来遍历 tabs 对象,渲染了一个 <button /> 元素的列表。对于每个渲染出来的 <button /> 元素,我们将选项卡的值传递给元素的 key 属性。当标签页被选择/激活时,动态地渲染一个 .active 类。在每个按钮的点击事件中添加一个处理方法,当按钮被点击时,处理方法会将对应的值更新到 currentTab 中。

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

<script setup>
  import { ref } from "vue";
  import Home from "./components/Home.vue";
  import Feed from "./components/Feed.vue";
  import History from "./components/History.vue";

  const currentTab = ref("Home");
  const tabs = {
    Home,
    Feed,
    History,
  };
</script>

这时我们就有了三个选项卡按钮了。

alt text

为了动态地渲染子元素,我们需要向 <component> 元素绑定一个 is 属性。传递给 is 的值应该是我们想要动态渲染的组件值。在我们的例子中,我们将使用 currentTab 来获取当前要渲染的组件。

vue
<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>

<script setup>
  import { ref } from "vue";
  import Home from "./components/Home.vue";
  import Feed from "./components/Feed.vue";
  import History from "./components/History.vue";

  // eslint-disable-next-line no-unused-vars
  const currentTab = ref("Home");

  // eslint-disable-next-line no-unused-vars
  const tabs = {
    Home,
    Feed,
    History,
  };
</script>

当动态组件 <component /> 元素放到我们的模板中时,我们注意到随着选项卡的切换,子组件动态地加载和卸载了。

在演练场中查看代码

保存状态

状态的保存是使用动态组件时一个很重要的考虑因素。默认情况下,当一个组件卸载时,它的状态也会丢失。然而,Vue 提供了一种在组件动态切换时也能保留状态的方法:<KeepAlive> 组件。

要保存动态组件中的状态,我们可以使用 <KeepAlive> 组件将 <component> 元素包裹起来。

vue
<template>
  <div class="demo">
    <!--  -->
    <KeepAlive>
      <component :is="tabs[currentTab]" class="tab"></component>
    </KeepAlive>
  </div>
</template>

<script setup>
  // ...
</script>

<component><KeepAlive> 包裹时,动态组件的状态将会在它们被卸载时保留下来。这意味着数据或组件状态将被保留,并且在组件重新挂载时将会恢复之前的状态。

我们修改之前的子组件,为它们添加一个简单的计数器。

vue
<!-- 在 Home、Feed、History 中都添加这个计数器示例 -->
<template>
  <div class="tab">
    Home component
    <p>Counter: {{ counter }}</p>
    <button @click="incrementCounter">Increment</button>
  </div>
</template>

<script setup>
  import { ref } from "vue";

  const counter = ref(0);

  // eslint-disable-next-line no-unused-vars
  const incrementCounter = () => {
    counter.value++;
  };
</script>

随着这些更改,我们注意到即使我们动态切换了组件,子组件中的计数器状态也会被保留。

通过使用 <KeepAlive> 组件,我们可以通过保留组件状态来增强动态组件的功能,并在选项卡切换时提供更流畅的用户体验。

在演练场中查看代码

扩展阅读

动态组件 | Vue 文档KeepAlive | Vue 文档

评论区
评论区空空如也
发送评论
名字
0 / 20
邮箱
0 / 100
评论内容
0 / 140
由于是非实名评论,所以不提供删除功能。如果你需要删除你发送的评论,或者是其他人的评论对你造成了困扰,请 发邮件给我 。同时评论区会使用 AI + 人工的方式进行审核,以达到合规要求。

© thebestxt.cc
辽ICP备16009524号-8
本站所有文章版权所有,转载请注明出处