Gernar
Frontend DeveloperVue и композиция компонентов

Интервью-вопрос

Что такое слоты

Слоты во Vue позволяют родителю передать разметку внутрь дочернего компонента. На практике это помогает делать гибкие карточки, модалки, списки и таблицы без передачи HTML строками и без лишних props.

Добавлен
Редакция

Подготовьте короткий ответ и пару деталей на случай уточняющих вопросов.

🐰0
🥚0

Мини-квиз

Проверка перед разбором

Несколько быстрых вопросов перед разбором. Так проще поймать места, которые только кажутся понятными.

Вопрос 1 из 50 правильно

Как лучше сказать про слоты на интервью?

Вы отвечаете коротко и хотите сразу показать, зачем они нужны в реальном UI.

Варианты ответа

Разбор

Разобраться, а не зазубрить

Дальше разбираем суть, типичные уточнения и места, где легко сказать лишнее или перепутать термины.

Базовая идея

Слот нужен, когда компонент не должен знать заранее всю разметку внутри себя. Он задает каркас, поведение и стили контейнера, а родитель передает содержимое.

Простой пример:

<!-- BaseCard.vue -->
<template>
  <article class="card">
    <slot>Нет содержимого</slot>
  </article>
</template>
<!-- Parent.vue -->
<BaseCard>
  <h2>Профиль</h2>
  <p>Данные пользователя загружены</p>
</BaseCard>

На интервью не ограничивайтесь словом "разметка". Добавьте практический вывод: слот делает компонент-контейнер переиспользуемым и помогает не передавать HTML через строковые props. Так вы снижаете XSS-риск и оставляете обработчики событий, реактивные данные и компоненты в обычном шаблоне Vue.

Props или slots

В сильном ответе важно показать границу. Если вы передаете значение, состояние или настройку, обычно нужен prop. Если вы передаете фрагмент интерфейса, обычно нужен slot.

Плохой вариант:

<BaseCard :header-html="'<h2>Profile</h2><button>Edit</button>'" />

Так делать не стоит. Строка хуже проверяется, неудобна для реактивности и может стать источником XSS, если ее потом вставить через v-html. Еще вы теряете обычные Vue-события и получаете UI, который сложнее тестировать. Безопаснее отдать родителю named slot.

<BaseCard>
  <template #header>
    <h2>Profile</h2>
    <button>Edit</button>
  </template>

  <p>User data</p>
</BaseCard>

Как выбрать между prop и slot

1Нужно передать строку, число, флаг или объект настроек?
Используйте prop. Так контракт проще типизировать и тестировать.
2Родитель должен сам задать разметку внутри компонента?
Используйте default или named slot. Это сохраняет компоненту роль контейнера.
3Компонент знает данные, но родитель выбирает их отображение?
Используйте scoped slot и явно передайте только нужные slot props.
4Компонент требует много слотов для каждой мелкой детали?
Проверьте дизайн API. Возможно, лучше разбить компонент или оставить часть поведения через props.

Default, named и scoped slots

Default slot это основной слот без имени. Он удобен для кнопки, карточки, модального окна или layout-обертки, где есть одно главное содержимое.

Named slots нужны, когда в компоненте есть несколько зон. Например, у карточки могут быть header, default-содержимое и footer.

<!-- BaseCard.vue -->
<template>
  <article class="card">
    <header><slot name="header" /></header>
    <main><slot /></main>
    <footer><slot name="footer" /></footer>
  </article>
</template>

Scoped slot нужен, когда дочерний компонент хочет передать данные наружу в шаблон слота. Например, список управляет итерацией, но родитель выбирает, как рисовать строку.

<!-- UserList.vue -->
<template>
  <ul>
    <li v-for="(user, index) in users" :key="user.id">
      <slot :user="user" :index="index" />
    </li>
  </ul>
</template>
<!-- Parent.vue -->
<UserList :users="users" v-slot="{ user, index }">
  <strong>{{ index + 1 }}. {{ user.name }}</strong>
</UserList>

Здесь UserList контролирует список, ключи и обход, а родитель контролирует внешний вид элемента. Это хороший пример для интервью. Он показывает не только синтаксис, но и разделение ответственности.

Важно не отдавать в slot весь внутренний state списка. Передавайте только стабильные значения, которые входят в публичный контракт. Так родитель не начнет зависеть от деталей реализации, а лишние изменения внутреннего состояния не будут без причины усложнять рендеринг слота.

Главная ловушка с областью видимости

Содержимое слота пишется в родительском компоненте, поэтому оно видит данные родителя. Оно не видит внутренние переменные дочернего компонента просто потому, что вставляется внутрь его шаблона.

Если вам нужны данные ребенка, передайте их явно:

<slot :item="item" :is-active="activeId === item.id" />

Не передавайте наружу токены, сырые ответы API или приватные поля только потому, что они есть в компоненте. Slot props становятся частью публичного API компонента и могут случайно попасть в DOM или аналитику.

На интервью проговорите это отдельно. Фраза "дочерний компонент передает данные в слот" точнее, чем "родитель получает доступ к дочернему компоненту". Второй вариант звучит так, будто нарушается инкапсуляция.

Практический вывод для frontend-кода

Слоты особенно полезны в компонентах, которые отвечают за поведение, но не должны навязывать конкретную разметку. Это модалки, dropdown, tabs, table, list, autocomplete, empty state и layout-компоненты.

Но слоты не должны превращать компонент в непонятный конструктор. Если у компонента десять named slots и каждый влияет на состояние, пользоваться им будет трудно. В такой ситуации лучше разделить компонент на меньшие части или оставить часть настроек через props.

Для интерактивных компонентов проверьте доступность контракта. Если слот меняет кнопку открытия dropdown или заголовок модалки, компонент должен сохранять фокус, закрытие с клавиатуры, корректные labels и понятное состояние ошибки. Иначе гибкость слота приведет к красивому, но небезопасному для пользователя UI.

На интервью можно ответить так:

Слоты я использую, когда нужно кастомизировать UI внутри переиспользуемого компонента. Props оставляю для данных и настроек. Если дочерний компонент управляет состоянием, но родитель должен отрисовать часть интерфейса, использую scoped slot и явно передаю только нужные данные.

Частые ошибки

Где обычно ошибаются

Проверьте формулировки, которые звучат уверенно, но на интервью быстро выдают пробелы.

  1. 1

    Передавать разметку строкой через prop

    Это ломает читаемость, усложняет экранирование и может привести к XSS, если потом использовать v-html. Для UI-фрагментов лучше использовать slot, а через prop передавать только данные или безопасные настройки.
  2. 2

    Ждать доступ к внутренним переменным компонента

    Обычный slot использует область видимости родителя. Если вы в слоте обращаетесь к переменной дочернего компонента, она не появится сама. Передайте нужные значения через scoped slot props.
  3. 3

    Делать scoped slot без четкого контракта

    Если компонент отдает наружу слишком много данных, родитель начинает зависеть от внутренней реализации. Лучше передавать минимальный набор значений, например item, index и selected, а внутренние детали оставить внутри компонента.
  4. 4

    Заменять слотами простые props

    Слот ради одного текста кнопки делает API тяжелее, чем нужно. Если пользователю компонента нужно только поменять label или variant, prop будет проще. Слот нужен, когда меняется структура, например иконка, бейдж или произвольная разметка.
  5. 5

    Отдавать через slot интерактивный UI без контракта доступности

    Если родитель передает в slot кнопку, ссылку или поле ввода, компонент все равно должен сохранять понятный фокус, keyboard flow и доступное имя. Иначе модалка, dropdown или карточка могут выглядеть правильно, но плохо работать с клавиатуры и скринридера.

Follow-up

Что могут спросить дальше

Короткие ответы на вопросы, которыми проверяют понимание slots, props и области видимости во Vue.

Живые ответы

Видео с похожим вопросом

Если найдем публичные интервью с таким вопросом, добавим их сюда. Их удобно смотреть после теории, чтобы свериться с живыми ответами.

Пока видео нет. Когда появятся подходящие публичные интервью, добавим их в этот блок, чтобы можно было сравнить разбор с тем, как отвечают реальные кандидаты.

Содержание