Компонент со слотом
На странице кафе есть несколько блоков, которые выглядят одинаково: белая рамка с заголовком, а внутри каждый раз что-то своё. Часы работы — это абзац, меню — список, заказ — список с кнопкой. Один компонент для такого блока пришёлся бы кстати, но пропсы тут не подходят. Проп несёт значение, например текст или объект, а этому блоку нужно нести кусок страницы.
Для этого у компонента есть слот: место в его шаблоне, которое заполняет родитель. Вот Panel.vue — блок с заголовком из пропса title и слотом под заголовком:
<script setup>
defineProps({
title: { type: String, required: true },
});
</script>
<template>
<section class="panel">
<h2>{{ title }}</h2>
<slot />
</section>
</template>Родитель пишет компонент с открывающим и закрывающим тегом и помещает содержимое между ними, как сделал бы с HTML-элементом:
<Panel title="Часы работы">
<p>Каждый день с 7:00 до 19:00.</p>
</Panel>Vue показывает шаблон панели, а содержимое ставит на место <slot />. Страница получает:
<section class="panel">
<h2>Часы работы</h2>
<p>Каждый день с 7:00 до 19:00.</p>
</section>Содержимым может быть всё, что вы пишете в шаблоне: текст, несколько элементов, список с v-for, даже другие компоненты. И при каждом использовании панели ей можно передать другое содержимое.
До сих пор между тегами ваших компонентов ничего не было, поэтому вы писали их самозакрывающимися, как <MenuItem />. А компонент без <slot /> ничего не делает с содержимым между своими тегами: Vue его пропускает, без предупреждения. Если содержимое не появляется, первым делом проверьте, есть ли у компонента слот.
Задание
- 1
В
Panel.vueпоставьте<slot />под заголовком, чтобы панель с часами работы показывала свой абзац. - 2
В
App.vueдобавьте вторую панель под первой, с заголовкомДесерт дняи абзацемМорковный торт с грецкими орехами, €4.