Что такое слоты?

Слоты (slots) — это механизм Vue для передачи шаблонного контента в компоненты. Они позволяют создавать гибкие, переиспользуемые компоненты с динамическим содержимым.
Базовые слоты
Родительский компонент:
<template>
<Card>
<p>Этот контент попадет в слот</p>
</Card>
</template>
<script setup>
import Card from './Card.vue'
</script>
Компонент Card.vue:
<template>
<div class="card">
<div class="card-header">
<h3>Заголовок карточки</h3>
</div>
<!-- Контент будет вставлен сюда -->
<slot></slot>
</div>
</template>
Именованные слоты
Родительский компонент:
<template>
<Layout>
<template v-slot:header>
<h1>Мой заголовок</h1>
</template>
<template v-slot:default>
<p>Основной контент</p>
</template>
<template v-slot:footer>
<p>© 2023 Мой сайт</p>
</template>
</Layout>
</template>
Компонент Layout.vue:
<template>
<div class="layout">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot> <!-- слот по умолчанию -->
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
Scoped Slots (Слоты с данными)
Компонент List.vue:
<template>
<ul>
<li v-for="(item, index) in items" :key="index">
<!-- Передаем данные item в слот -->
<slot :item="item" :index="index"></slot>
</li>
</ul>
</template>
<script setup>
defineProps<{
type: string[];
}>();
</script>
Родительский компонент:
<template>
<List :items="users">
<!-- Получаем данные через v-slot -->
<template v-slot="{ item, index }">
<p>{{ index + 1 }}. {{ item.name }} ({{ item.age }})</p>
</template>
</List>
</template>
<script setup>
import List from './List.vue'
const users = [
{ name: 'Алексей', age: 28 },
{ name: 'Мария', age: 24 }
]
</script>
Динамические имена слотов
<template>
<DynamicSlot>
<template v-slot:[dynamicSlotName]>
Контент для динамического слота
</template>
</DynamicSlot>
</template>
<script setup>
import { ref } from 'vue'
import DynamicSlot from './DynamicSlot.vue'
const dynamicSlotName = ref('header')
</script>
Практические советы
- Сокращенный синтаксис: v-slot:header → #header
- Fallback контент: можно задать содержимое по умолчанию
<slot>Запасной контент, если ничего не передано</slot>
Заключение
- Обычные слоты — для базового контента
- Именованные слоты — для точного позиционирования
- Scoped slots — для передачи данных в родительский компонент
- Динамические слоты — для гибких сценариев
Домашнее задание
- Создайте компонент Tabs с использованием слотов
- Реализуйте компонент DataTable с scoped slots для кастомного отображения строк
- Поэкспериментируйте с динамическими именами слотов
<!-- Пример Tabs.vue -->
<template>
<div class="tabs">
<div class="tab-header">
<slot name="header"></slot>
</div>
<div class="tab-content">
<slot></slot>
</div>
</div>
</template>