Именованные и scoped слоты

Слоты во Vue.js используются для композиции компонентов и передачи разметки извне внутрь компонента. Именованные и scoped слоты расширяют базовый механизм, позволяя строить гибкие, переиспользуемые интерфейсные компоненты без жёсткой привязки к структуре DOM.


По умолчанию компонент имеет один слот без имени. Для размещения нескольких независимых областей вставки применяются именованные слоты.

Объявление именованных слотов в компоненте

<!-- BaseLayout.vue -->
<template>
  <header>
    <slot name="header"></slot>
  </header>

  <main>
    <slot></slot>
  </main>

  <footer>
    <slot name="footer"></slot>
  </footer>
</template>

Здесь:

  • слот без имени является дефолтным;
  • слоты header и footer — именованные.

Использование именованных слотов

<BaseLayout>
  <template v-slot:header>
    <h1>Заголовок страницы</h1>
  </template>

  <p>Основное содержимое</p>

  <template v-slot:footer>
    <small>Подвал</small>
  </template>
</BaseLayout>

Ключевые особенности:

  • v-slot используется только на <template> или компоненте;
  • содержимое вне <template v-slot:...> автоматически попадает в дефолтный слот.

Сокращённый синтаксис

<template #header>
  <h1>Заголовок</h1>
</template>

# является сокращением для v-slot: и применяется повсеместно в актуальном коде Vue 3.


Контент по умолчанию (fallback)

Если слот не был передан, компонент может отобразить запасное содержимое.

<slot name="footer">
  <span>Значение по умолчанию</span>
</slot>

Fallback-контент отображается только при отсутствии соответствующего слота у компонента-потребителя.


Scoped слоты

Scoped слоты позволяют компоненту передавать данные во внешний шаблон слота. Это основной механизм разделения логики и представления.

Передача данных из компонента

<!-- UserList.vue -->
<template>
  <ul>
    <li v-for="user in users" :key="user.id">
      <slot :user="user" :is-active="user.active"></slot>
    </li>
  </ul>
</template>

<script>
export default {
  props: {
    users: Array
  }
}
</script>

Атрибуты слота (:user, :is-active) формируют объект параметров слота.

Получение данных в слоте

<UserList :users="users">
  <template #default="{ user, isActive }">
    <span :class="{ active: isActive }">
      {{ user.name }}
    </span>
  </template>
</UserList>

Принцип работы:

  • данные передаются из дочернего компонента наружу;
  • внешний шаблон полностью контролирует разметку;
  • дочерний компонент отвечает за данные и цикл.

Scoped + именованные слоты

Именованные слоты также могут быть scoped.

Объявление

<slot name="item" :value="item" :index="index"></slot>

Использование

<template #item="{ value, index }">
  <div>{{ index }} — {{ value }}</div>
</template>

Такой подход часто применяется в списках, таблицах, дропдаунах, календарях.


Деструктуризация и псевдонимы

Scoped-слоты поддерживают стандартную деструктуризацию JavaScript.

<template #default="{ user: u }">
  {{ u.name }}
</template>

Допустимо задание значений по умолчанию:

<template #default="{ isActive = false }">
  {{ isActive }}
</template>

Динамические имена слотов

Vue поддерживает вычисляемые имена слотов.

<template v-slot:[slotName]>
  Динамический слот
</template>

slotName — строковое значение, определённое в контексте компонента.

Применение:

  • табы;
  • сложные layout-системы;
  • UI-конструкторы.

Проброс слотов (slot forwarding)

Компонент может передавать полученные слоты дальше, не зная их структуры.

<template>
  <ChildComponent>
    <slot name="header"></slot>
    <slot></slot>
  </ChildComponent>
</template>

Для scoped-слотов используется проброс параметров:

<slot name="item" v-bind="slotProps"></slot>

Множественные scoped-слоты в одном компоненте

<template>
  <slot name="title" :count="items.length"></slot>
  <slot name="item" v-for="item in items" :item="item"></slot>
</template>

Использование:

<MyComponent>
  <template #title="{ count }">
    Всего: {{ count }}
  </template>

  <template #item="{ item }">
    {{ item.name }}
  </template>
</MyComponent>

Отличие scoped-слотов от props

Props:

  • передаются сверху вниз;
  • определяют поведение компонента.

Scoped-слоты:

  • передают данные снизу вверх;
  • определяют отображение.

Scoped-слоты используются, когда компонент:

  • управляет данными;
  • не должен диктовать HTML-структуру.

Типичные сценарии использования

  • таблицы данных;
  • списки с кастомным рендерингом;
  • dropdown и autocomplete;
  • layout-компоненты;
  • headless UI-компоненты.

Ограничения и особенности

  • слот не имеет собственного реактивного контекста — используется контекст родителя;
  • нельзя использовать v-slot вне компонента;
  • scoped-слоты не заменяют состояние компонента, а дополняют его;
  • порядок вычисления соответствует обычному рендеру Vue.

Сравнение синтаксиса Vue 2 и Vue 3

Vue 3 унифицировал API:

  • slot-scope удалён;
  • используется только v-slot;
  • # — стандартный шорткат;
  • единый синтаксис для дефолтных и именованных слотов.

Это делает код компактнее и предсказуемее при масштабировании.


Именованные и scoped слоты формируют основу архитектуры компонентных библиотек во Vue.js, позволяя строить абстрактные компоненты с чётким разделением ответственности между логикой и представлением.