dynamic-components
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDynamic Components
动态组件
Table of Contents
目录
Dynamic components constitute the ability to dynamically change (i.e. switch) between components by binding an attribute to the reserved element.
is<component>We'll go through an example to best understand how dynamic components work. Assume we have separate components titled , , and that simply display text dictating what component it is.
HomeFeedHistoryWhen to Use
使用场景
- Use this when you need to render different components based on user interaction (e.g., tabs, views)
- This is helpful as an alternative to multiple /
v-ifblocks for conditional component renderingv-else
- 当你需要根据用户交互(如标签页、视图切换)渲染不同组件时使用
- 这可以作为多个/
v-if条件渲染组件的替代方案,更为便捷v-else
Instructions
操作步骤
- Bind the attribute on
isto a reactive value referencing the component definition<component> - Use a object mapping names to imported component definitions
tabs - Wrap with
<component>to preserve state when switching between dynamic components<KeepAlive>
- 将上的
<component>属性绑定到一个引用组件定义的响应式值is - 使用一个对象,将组件名称映射到导入的组件定义
tabs - 使用包裹
<KeepAlive>,以在切换动态组件时保留状态<component>
Details
详细说明
html
<!-- 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>Our goal is to build an interface that surfaces a list of tabs that can be clicked. Depending on what tab is clicked, we want to dynamically render a certain component.
When clicking between the tabs, we want components to be dynamically unmounted and mounted without the use of routing. Though something like this could be achieved by conditionally rendering child templates with the help of directives like and , this is a perfect use case of Vue dynamic components.
v-ifv-elseIn the parent component of our app, we can first import the three individual components to have them available in the template. We'll also create a reactive property that is given an initial value of .
AppcurrentTab"Home"html
<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>Note that our object references the actual component definitions and not just the component names.
tabsIn the component template, we'll look to render three separate tab buttons — one for each component we intend to display. We'll use the directive to help achieve this.
Appv-forhtml
<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>To dynamically render a certain child component, we'll bind an attribute to the reserved element. The value attached to the attribute should correspond to the child component that we want to render dynamically.
is<component>ishtml
<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";
const currentTab = ref("Home");
const tabs = {
Home,
Feed,
History,
};
</script>With the dynamic element placed in our template, the child components are now dynamically unmounted and mounted depending on which tab has been selected.
<component />html
<!-- 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>我们的目标是构建一个包含可点击标签列表的界面,根据点击的标签动态渲染对应的组件。
在切换标签时,我们希望组件能动态卸载和挂载,且无需使用路由。虽然可以通过和等指令条件渲染子模板来实现类似效果,但这正是Vue动态组件的理想用例。
v-ifv-else在应用的父组件中,我们首先导入这三个独立组件,以便在模板中使用。同时创建一个初始值为的响应式属性。
App"Home"currentTabhtml
<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在组件的模板中,我们将渲染三个独立的标签按钮,每个按钮对应一个要显示的组件。我们使用指令来实现这一点。
Appv-forhtml
<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>为了动态渲染某个子组件,我们需要给保留的元素绑定属性。属性的值应与我们要动态渲染的子组件相对应。
<component>isishtml
<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";
const currentTab = ref("Home");
const tabs = {
Home,
Feed,
History,
};
</script>在模板中添加动态元素后,子组件现在会根据选中的标签动态卸载和挂载。
<component />Preserving state
状态保留
Preserving state can be an important consideration to keep in mind when using dynamic components. By default, when a component is unmounted, its state is lost. However, Vue provides a way to preserve the state of dynamic components using the component.
<KeepAlive>To preserve the state of dynamic components, we can wrap the element with the component.
<component><KeepAlive>html
<template>
<div class="demo">
<!-- -->
<KeepAlive>
<component :is="tabs[currentTab]" class="tab"></component>
</KeepAlive>
</div>
</template>
<script setup>
// ...
</script>With the component wrapping the element, the state of the dynamic components will be preserved when they are unmounted. This means that any data or component state will be maintained, and the component will retain its previous state when it is mounted again.
<KeepAlive><component>To see an example of this, we can update each of our child components to contain a simple counter that increments.
html
<!-- Repeat this counter example for Home, Feed, and 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);
const incrementCounter = () => {
counter.value++;
};
</script>With these changes, the counter state for each respective child component is kept preserved even as we dynamically switch between components.
By using the component, we can enhance the behavior of dynamic components by preserving their state and providing a smoother user experience when switching between tabs.
<KeepAlive>在使用动态组件时,状态保留是一个需要考虑的重要因素。默认情况下,组件卸载时其状态会丢失。不过,Vue提供了组件来保留动态组件的状态。
<KeepAlive>要保留动态组件的状态,我们可以用包裹元素。
<KeepAlive><component>html
<template>
<div class="demo">
<!-- -->
<KeepAlive>
<component :is="tabs[currentTab]" class="tab"></component>
</KeepAlive>
</div>
</template>
<script setup>
// ...
</script>用组件包裹元素后,动态组件在卸载时其状态会被保留。这意味着任何数据或组件状态都会被维持,当组件再次挂载时会恢复之前的状态。
<KeepAlive><component>为了直观展示这一点,我们可以更新每个子组件,添加一个简单的计数器用于递增。
html
<!-- 为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);
const incrementCounter = () => {
counter.value++;
};
</script>经过这些修改后,即使我们在动态组件之间切换,每个子组件的计数器状态也会被保留。
通过使用组件,我们可以增强动态组件的行为,保留其状态,在切换标签页时为用户提供更流畅的体验。
<KeepAlive>