Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое scoped slot?
Scoped slot (областной слот) — это мощный паттерн в Vue.js, который позволяет родительскому компоненту получить доступ к данным из дочернего компонента при рендеринге шаблона. В отличие от обычных слотов, где дочерний компонент контролирует содержимое, scoped slots предоставляют данные от дочернего компонента, которые родитель может использовать для рендеринга.
Базовый пример scoped slot
// ДочерниеComponent.vue
<template>
<div>
<h3>{{ title }}</h3>
<ul>
<li v-for="item in items" :key="item.id">
<slot name="item" :item="item" :index="index">
{{ item.name }}
</slot>
</li>
</ul>
</div>
</template>
<script setup>
defineProps({
title: String,
items: Array
});
</script>
// РодительскийComponent.vue
<template>
<ChildComponent :title=""Items"" :items="items">
<template #item="{ item, index }">
<strong>{{ index + 1 }}. {{ item.name }} - {{ item.price }}$</strong>
</template>
</ChildComponent>
</template>
Как это работает внутри
// Дочерний компонент определяет слот и передаёт данные
<slot name="item" :item="item" :index="index">
// Эти данные становятся доступны в родительском компоненте
<template #item="{ item, index }">
{{ item.name }}
</template>
// Vue распаковывает объект и делает item и index доступными в шаблоне
Пример: Таблица с кастомным форматированием
// DataTable.vue
<template>
<table>
<thead>
<tr>
<th v-for="column in columns" :key="column.key">
{{ column.label }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(row, rowIndex) in data" :key="rowIndex">
<td v-for="column in columns" :key="column.key">
<slot
:name="`cell-${column.key}`"
:row="row"
:column="column"
:value="row[column.key]"
:rowIndex="rowIndex"
>
{{ row[column.key] }}
</slot>
</td>
</tr>
</tbody>
</table>
</template>
// В родительском компоненте
<template>
<DataTable :columns="columns" :data="users">
<template #cell-status="{ value }">
<span :class="`badge badge-${value.toLowerCase()}`">
{{ value }}
</span>
</template>
<template #cell-actions="{ row }">
<button @click="editUser(row)">Edit</button>
<button @click="deleteUser(row)">Delete</button>
</template>
</DataTable>
</template>
Продвинутый пример: Modal с контролем содержимого
// Modal.vue
<template>
<div v-if="isOpen" class="modal-overlay" @click="closeModal">
<div class="modal-content" @click.stop>
<div class="modal-header">
<slot name="header" :title="title">
<h2>{{ title }}</h2>
</slot>
</div>
<div class="modal-body">
<slot :data="data" :loading="loading">
<p>No content provided</p>
</slot>
</div>
<div class="modal-footer">
<slot name="footer" :close="closeModal" :submit="submitModal">
<button @click="closeModal">Cancel</button>
<button @click="submitModal">OK</button>
</slot>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
const props = defineProps({
title: String,
data: Object
});
const emit = defineEmits(["update:open", "submit"]);
const isOpen = ref(true);
const loading = ref(false);
const closeModal = () => {
isOpen.value = false;
emit("update:open", false);
};
const submitModal = async () => {
loading.value = true;
loading.value = false;
emit("submit");
closeModal();
};
</script>
Отличие обычного слота от scoped slot
// Обычный слот: родитель НЕ имеет доступ к данным дочернего
<slot>Default content</slot>
// Scoped slot: родитель ИМЕЕТ доступ к данным дочернего
<slot :item="item" :index="index">Default content</slot>
// Использование
<MyComponent>
<template #default="{ item, index }">
{{ index }}: {{ item.name }}
</template>
</MyComponent>
Когда использовать scoped slots?
// Используй для:
// 1. Компонентов с логикой, но без контроля представления
// 2. Повторяемых элементов (списки, таблицы)
// 3. Модальных окон, drawer-ов, dropdown-ов
// 4. Компонентов с условным рендерингом
// Не используй если:
// 1. Компонент полностью управляет представлением
// 2. Нет необходимости передавать данные родителю
// 3. Достаточно простого наследования props