В Vuetify система слотов является ключевым механизмом для расширяемости компонентов. Slots позволяют вставлять пользовательский контент внутрь компонентов, сохраняя их функциональность и дизайн. В отличие от простого вложения элементов в шаблон, слоты обеспечивают более гибкую и структурированную интеграцию.
Простейший вариант использования слотов — это дефолтный слот. Он передает содержимое из родительского компонента внутрь дочернего.
<template>
<v-card>
<slot>Здесь будет контент по умолчанию</slot>
</v-card>
</template>
Если при использовании компонента не передан контент, отобразится текст из дефолтного слота. Если передан — он заменит стандартное содержимое:
<v-card>
<p>Пользовательский контент</p>
</v-card>
Для более сложных компонентов применяются именованные слоты, которые позволяют управлять различными частями компонента отдельно.
<template>
<v-dialog>
<template v-slot:activator="{ on, attrs }">
<v-btn v-bind="attrs" v-on="on">Открыть диалог</v-btn>
</template>
<v-card>
<slot name="header">Заголовок по умолчанию</slot>
<slot name="body">Тело по умолчанию</slot>
<slot name="footer">Футер по умолчанию</slot>
</v-card>
</v-dialog>
</template>
При использовании компонента можно передать содержимое в конкретный слот:
<my-dialog>
<template v-slot:header>
<h3>Пользовательский заголовок</h3>
</template>
<template v-slot:body>
<p>Основной текст диалога</p>
</template>
<template v-slot:footer>
<v-btn color="primary">Подтвердить</v-btn>
</template>
</my-dialog>
Scoped slots предоставляют доступ к данным дочернего
компонента. Это особенно полезно для компонентов типа
v-data-table или v-select, где требуется
динамическое управление содержимым.
<v-data-table
:items="users"
:headers="headers"
>
<template v-slot:item.name="{ item }">
<strong>{{ item.name }}</strong>
</template>
<template v-slot:item.email="{ item }">
<em>{{ item.email }}</em>
</template>
</v-data-table>
В этом примере item передается в слот, что позволяет
кастомизировать вывод каждой строки таблицы. Ключевой
момент — объект, переданный в слот, всегда содержит актуальные
данные компонента.
Vuetify позволяет создавать динамические слоты, имя
которых задается через переменную. Это особенно удобно для компонентов с
множеством повторяющихся элементов, например, в v-tabs или
v-carousel.
<v-tabs v-model="tab">
<v-tab v-for="t in tabs" :key="t">{{ t.label }}</v-tab>
<v-tab-item v-for="t in tabs" :key="t.name">
<template v-slot:[`default`]>
<p>{{ t.content }}</p>
</template>
</v-tab-item>
</v-tabs>
С помощью синтаксиса v-slot:[name] можно задавать имена
слотов динамически, что повышает гибкость компонентов и уменьшает
дублирование кода.
Многие компоненты Vuetify уже используют слоты для расширяемости.
Например, v-select позволяет полностью кастомизировать
каждый элемент списка:
<v-select
:items="fruits"
label="Выберите фрукт"
>
<template v-slot:item="{ item }">
<v-list-item>
<v-list-item-content>
<v-list-item-title>
? {{ item.name }}
</v-list-item-title>
</v-list-item-content>
</v-list-item>
</template>
</v-select>
Здесь стандартный рендеринг элементов заменяется на кастомный, включая иконки, стили и дополнительные элементы. Это делает слоты инструментом полной визуальной кастомизации.
Если в компоненте определены слоты, но пользователь не передает
контент, отображается fallback содержимое, которое
прописано внутри <slot>.
<slot name="header">Стандартный заголовок</slot>
Такой подход гарантирует, что интерфейс всегда будет корректным, даже при отсутствии пользовательского контента.
Использование системы слотов в Vuetify обеспечивает гибкость, модульность и расширяемость компонентов, позволяя создавать интерфейсы любого уровня сложности без необходимости переписывать исходный код библиотеки.