Динамические компоненты — это мощный механизм Vue.js, позволяющий переключать компоненты «на лету». Они особенно полезны при создании интерфейсов с вкладками, мастеров настройки или любых других случаях, когда необходимо динамически менять содержимое
- Component и :is
- Базовое использование
- Передача пропсов
- Keep-alive
- Сохранение состояния компонента
- Включение/исключение компонентов
- Хуки жизненного цикла
- Асинхронные компоненты
- Базовая загрузка
- Продвинутая конфигурация
- Transitions
- Базовые переходы
- Режимы перехода
- Slots
- Базовые слоты
- Скоупированные слоты
- Телепортация компонентов
- Базовое использование
- Условная телепортация
- Практический пример
Component и :is
Базовое использование
Компонент <component>
с атрибутом is
позволяет динамически переключать компоненты:
<template>
<div>
<button
v-for="tab in tabs"
:key="tab"
@click="currentTab = tab"
>
{{ tab }}
</button>
<component :is="currentTab"></component>
</div>
</template>
<script>
import TabHome from './components/TabHome.vue'
import TabPosts from './components/TabPosts.vue'
import TabArchive from './components/TabArchive.vue'
export default {
components: {
TabHome,
TabPosts,
TabArchive
},
data() {
return {
currentTab: 'TabHome',
tabs: ['TabHome', 'TabPosts', 'TabArchive']
}
}
}
</script>
Передача пропсов
Динамическим компонентам можно передавать пропсы:
<component
:is="currentTab"
:title="tabTitle"
@custom-event="handleEvent"
/>
Keep-alive
Сохранение состояния компонента
<keep-alive>
позволяет сохранять состояние компонентов при переключении:
<template>
<div>
<keep-alive>
<component :is="currentTab"></component>
</keep-alive>
</div>
</template>
Включение/исключение компонентов
Можно указать, какие компоненты нужно кэшировать:
<keep-alive :include="['TabHome', 'TabPosts']" :exclude="['TabArchive']">
<component :is="currentTab"></component>
</keep-alive>
Хуки жизненного цикла
При использовании keep-alive
доступны специальные хуки:
export default {
name: 'TabHome',
activated() {
// Вызывается при восстановлении компонента из кэша
console.log('Component activated')
},
deactivated() {
// Вызывается при помещении компонента в кэш
console.log('Component deactivated')
}
}
Асинхронные компоненты
Базовая загрузка
Асинхронная загрузка компонентов для оптимизации производительности:
<script>
export default {
components: {
AsyncComponent: () => import('./AsyncComponent.vue')
}
}
</script>
Продвинутая конфигурация
Настройка загрузки с обработкой состояний:
const AsyncComponent = () => ({
component: import('./AsyncComponent.vue'),
loading: LoadingComponent,
error: ErrorComponent,
delay: 200,
timeout: 3000
})
Transitions
Базовые переходы
Анимация при переключении компонентов:
<template>
<transition name="fade">
<component :is="currentTab"></component>
</transition>
</template>
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
</style>
Режимы перехода
<transition name="fade" mode="out-in">
<component :is="currentTab"></component>
</transition>
Slots
Базовые слоты
Использование слотов для гибкой компоновки:
<!-- BaseLayout.vue -->
<template>
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
<!-- Использование -->
<base-layout>
<template v-slot:header>
<h1>Заголовок</h1>
</template>
<template v-slot:default>
<p>Основной контент</p>
</template>
<template v-slot:footer>
<p>Подвал</p>
</template>
</base-layout>
Скоупированные слоты
Передача данных через слоты:
<!-- ItemList.vue -->
<template>
<ul>
<li v-for="item in items" :key="item.id">
<slot :item="item">
{{ item.text }}
</slot>
</li>
</ul>
</template>
<!-- Использование -->
<item-list :items="items">
<template v-slot:default="slotProps">
<strong>{{ slotProps.item.text }}</strong>
</template>
</item-list>
Телепортация компонентов
Базовое использование
Телепортация содержимого в другую часть DOM:
<template>
<div>
<teleport to="body">
<div class="modal">
<h2>Модальное окно</h2>
<slot></slot>
<button @click="closeModal">Закрыть</button>
</div>
</teleport>
</div>
</template>
Условная телепортация
<teleport to="#modal" :disabled="!shouldTeleport">
<div class="modal">
<!-- содержимое модального окна -->
</div>
</teleport>
Практический пример
Создадим табы с анимированным переключением и сохранением состояния:
<template>
<div class="tabs-container">
<div class="tabs-buttons">
<button
v-for="tab in tabs"
:key="tab.name"
:class="['tab-button', { active: currentTab === tab.name }]"
@click="currentTab = tab.name"
>
{{ tab.label }}
</button>
</div>
<keep-alive>
<transition name="fade" mode="out-in">
<component
:is="currentTab"
:data="tabData"
@update="handleUpdate"
></component>
</transition>
</keep-alive>
<teleport to="#modal-container" v-if="showModal">
<div class="modal">
<!-- Модальное окно -->
</div>
</teleport>
</div>
</template>
<script>
export default {
data() {
return {
currentTab: 'TabHome',
showModal: false,
tabs: [
{ name: 'TabHome', label: 'Главная' },
{ name: 'TabPosts', label: 'Посты' },
{ name: 'TabArchive', label: 'Архив' }
],
tabData: {}
}
},
methods: {
handleUpdate(data) {
this.tabData = data
}
}
}
</script>
<style scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.tab-button {
padding: 10px 20px;
margin: 5px;
border: none;
cursor: pointer;
}
.tab-button.active {
background-color: #42b983;
color: white;
}
</style>
Еще больше уроков для изучения Vue