Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое слоты
Слоты (slots) — это мощный механизм в веб-компонентах и фреймворках (особенно в Vue.js), который позволяет родительскому компоненту передавать содержимое во вложенные компоненты. Слоты обеспечивают гибкость и переиспользуемость компонентов, позволяя переопределять части разметки без изменения самого компонента.
Концепция слотов
Слот — это плейсхолдер или заполнитель в компоненте, который может быть заполнен содержимым из родительского компонента. Это похоже на параметры функции, но для HTML и компонентов.
Слоты в Vue.js
Основной слот (Named Slot)
// Card.vue — компонент с слотом
<template>
<div class="card">
<div class="card-header">
<slot name="header">Default Header</slot>
</div>
<div class="card-body">
<slot>Default Content</slot>
</div>
<div class="card-footer">
<slot name="footer">Default Footer</slot>
</div>
</div>
</template>
<style>
.card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 16px;
}
</style>
Использование слотов в родительском компоненте
// App.vue
<template>
<Card>
<template #header>
<h2>My Custom Header</h2>
</template>
<template #default>
<p>This is custom content for the card</p>
</template>
<template #footer>
<button>Click me</button>
</template>
</Card>
</template>
Сокращенный синтаксис: #header вместо v-slot:header
Безымянный слот (Default Slot)
Если у компонента только один слот, можно использовать безымянный:
// Button.vue
<template>
<button class="btn">
<slot>Click me</slot>
</button>
</template>
// Использование
<Button>Save Changes</Button>
Слоты с областью видимости (Scoped Slots)
Позволяют передавать данные из дочернего компонента в родительский:
// UserList.vue — компонент с данными
<template>
<div class="user-list">
<div v-for="user in users" :key="user.id" class="user-item">
<slot name="user" :user="user">
{{ user.name }}
</slot>
</div>
</div>
</template>
<script>
export default {
data() {
return {
users: [
{ id: 1, name: 'Alice', status: 'active' },
{ id: 2, name: 'Bob', status: 'inactive' }
]
}
}
}
</script>
// App.vue — использование с доступом к user
<template>
<UserList>
<template #user="{ user }">
<div class="custom-user">
<strong>{{ user.name }}</strong>
<span :class="user.status">{{ user.status }}</span>
</div>
</template>
</UserList>
</template>
Слоты в веб-компонентах
<!-- modal.js -->
<template id="modal-template">
<style>
.modal {
border: 1px solid #333;
padding: 20px;
border-radius: 8px;
}
.modal-header {
font-weight: bold;
margin-bottom: 10px;
}
.modal-body {
margin: 10px 0;
}
</style>
<div class="modal">
<div class="modal-header">
<slot name="header">Default Header</slot>
</div>
<div class="modal-body">
<slot>Default Content</slot>
</div>
</div>
</template>
<script>
class Modal extends HTMLElement {
connectedCallback() {
const template = document.getElementById('modal-template');
const clone = template.content.cloneNode(true);
this.attachShadow({ mode: 'open' }).appendChild(clone);
}
}
customElements.define('custom-modal', Modal);
</script>
<!-- Использование -->
<custom-modal>
<span slot="header">Important</span>
<p>This is important information</p>
</custom-modal>
Практические примеры
Компонент Dialog
// Dialog.vue
<template>
<div v-if="isOpen" class="dialog-overlay">
<div class="dialog">
<div class="dialog-header">
<slot name="header"></slot>
<button @click="close">×</button>
</div>
<div class="dialog-body">
<slot></slot>
</div>
<div class="dialog-footer">
<slot name="footer">
<button @click="close">Close</button>
</slot>
</div>
</div>
</div>
</template>
<script>
export default {
props: ['isOpen'],
emits: ['close'],
methods: {
close() {
this.$emit('close');
}
}
}
</script>
// Использование
<Dialog :isOpen="showDialog" @close="showDialog = false">
<template #header>
<h3>Confirm Action</h3>
</template>
<p>Are you sure?</p>
<template #footer>
<button @click="confirm">Yes</button>
<button @click="close">No</button>
</template>
</Dialog>
Таблица с кастомизацией ячеек
// DataTable.vue
<template>
<table>
<thead>
<tr>
<th v-for="col in columns" :key="col">
{{ col }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="row in rows" :key="row.id">
<td v-for="col in columns" :key="col">
<slot :name="col" :value="row[col]">
{{ row[col] }}
</slot>
</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
props: ['columns', 'rows']
}
</script>
// Использование
<DataTable :columns="['name', 'email', 'status']" :rows="users">
<template #status="{ value }">
<span :class="`badge-${value}`">{{ value }}</span>
</template>
</DataTable>
Преимущества слотов
- Переиспользуемость: один компонент для разных сценариев
- Гибкость: родитель контролирует содержимое
- Разделение ответственности: компонент отвечает за стиль, родитель — за содержание
- Типизация: с TypeScript можно типизировать слоты
- Реактивность: слоты реактивны и обновляются при изменении данных
Итоги
- Слоты — механизм для передачи содержимого в компоненты
- Существуют именованные слоты и безымянные слоты
- Scoped slots позволяют передавать данные в обратном направлении
- Слоты есть в Vue.js, веб-компонентах и других фреймворках
- Основной инструмент для создания гибких переиспользуемых компонентов