Code Example 1: Базовое использование слота
Что произойдёт с содержимым, переданным между тегами <Card> и </Card>? Где оно окажется в итоговом HTML?
<!-- Card.vue -->
<template>
<div class="card">
<slot></slot>
</div>
</template>
<!-- App.vue -->
<template>
<Card>
<h2>Заголовок карточки</h2>
<p>Текст карточки</p>
</Card>
</template>
Code Example 2: Fallback content
Что покажет каждый из этих двух вариантов использования компонента Button? Что такое fallback content?
<!-- Button.vue -->
<template>
<button class="btn">
<slot>Кнопка</slot>
</button>
</template>
<!-- Использование -->
<template>
<Button />
<Button>Отправить</Button>
</template>
Code Example 3: Карточка с контентом
Какой HTML будет сгенерирован в результате? Что произойдёт, если использовать <Card /> без передачи контента?
<!-- Card.vue -->
<template>
<div class="card">
<div class="card-body">
<slot>Контент карточки</slot>
</div>
</div>
</template>
<style scoped>
.card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 16px;
}
</style>
<!-- App.vue -->
<script setup>
import Card from './Card.vue'
</script>
<template>
<Card>
<h3>Профиль пользователя</h3>
<p>Имя: Иван</p>
<p>Email: ivan@example.com</p>
</Card>
</template>
Code Example 4: Модальное окно со слотом
Как слот помогает сделать модальное окно универсальным? Какой контент будет отображён внутри модалки?
<!-- Modal.vue -->
<script setup>
defineProps(['isOpen'])
const emit = defineEmits(['close'])
</script>
<template>
<div v-if="isOpen" class="modal-overlay" @click="emit('close')">
<div class="modal-content" @click.stop>
<slot>Содержимое модального окна</slot>
<button @click="emit('close')">Закрыть</button>
</div>
</div>
</template>
<!-- App.vue -->
<script setup>
import { ref } from 'vue'
import Modal from './Modal.vue'
const showModal = ref(false)
</script>
<template>
<button @click="showModal = true">Открыть</button>
<Modal :is-open="showModal" @close="showModal = false">
<h2>Подтверждение</h2>
<p>Вы уверены, что хотите удалить?</p>
</Modal>
</template>
Code Example 5: Кнопка с иконкой
Что отобразит каждый из трёх вариантов использования IconButton? Когда сработает fallback content?
<!-- IconButton.vue -->
<template>
<button class="icon-btn">
<slot>
Нажми меня
</slot>
</button>
</template>
<!-- App.vue -->
<template>
<IconButton>
<span>🗑️</span>
<span>Удалить</span>
</IconButton>
<IconButton>
<span>❤️</span>
</IconButton>
<IconButton />
</template>
Code Example 6: Область видимости слота
Почему userName доступен в контенте слота? К каким данным имеет доступ контент, переданный в слот?
<!-- Parent.vue -->
<script setup>
import { ref } from 'vue'
import Card from './Card.vue'
const userName = ref('Иван')
</script>
<template>
<Card>
<h2>Привет, {{ userName }}!</h2>
</Card>
</template>
Code Example 7: Props vs Slots
Сравните два подхода к передаче контента в компонент. Когда лучше использовать props, а когда slots?
Props:
<!-- Передача через props -->
<Card title="Заголовок" description="Описание" />
<!-- Card.vue -->
<template>
<div class="card">
<h2>{{ title }}</h2>
<p>{{ description }}</p>
</div>
</template>
Slots:
<!-- Передача через slot -->
<Card>
<h2>Заголовок</h2>
<p>Описание</p>
<button>Действие</button>
</Card>
<!-- Card.vue -->
<template>
<div class="card">
<slot></slot>
</div>
</template>
Code Example 8: Пограничные кейсы
В чём разница между <Card /> и <Card></Card> с точки зрения fallback content? Что произойдёт в каждом случае?
<Card>
<h2>Заголовок</h2>
<p>Параграф 1</p>
<p>Параграф 2</p>
<button>Кнопка</button>
</Card>
<!-- Не передано ничего -->
<Card />
<!-- Передан пустой контент -->
<Card></Card>
Code Example 9: Динамический контент в слоте
Можно ли использовать директивы Vue (например, v-for) внутри контента слота? Что будет отрисовано?
<script setup>
import { ref } from 'vue'
const items = ref(['Яблоко', 'Банан', 'Апельсин'])
</script>
<template>
<Card>
<ul>
<li v-for="item in items" :key="item">{{ item }}</li>
</ul>
</Card>
</template>