Scoped slots

Scoped slots — это механизм, который позволяет передавать данные из дочернего компонента в слот родителя, создавая динамические и настраиваемые интерфейсы. В отличие от обычных слотов, которые просто отображают переданный контент, scoped slots предоставляют контекстные данные, доступные внутри слота, что делает их незаменимыми при работе с повторяющимися компонентами, таблицами, списками и динамическими элементами UI.


Основы использования scoped slots

В Vuetify каждый компонент с поддержкой scoped slots предоставляет объект с данными, доступными в слоте через директиву v-slot. Синтаксис выглядит следующим образом:

<v-data-table :items="users">
  <template v-slot:item="{ item }">
    <tr>
      <td>{{ item.name }}</td>
      <td>{{ item.email }}</td>
      <td>{{ item.role }}</td>
    </tr>
  </template>
</v-data-table>

Разбор примера:

  • v-data-table — компонент Vuetify для отображения таблиц.
  • v-slot:item — слот для рендеринга каждой строки таблицы.
  • { item } — деструктуризация объекта, который предоставляет компонент (каждая строка данных). Через item можно получить свойства каждой записи.

Деструктуризация объектов слота

Scoped slots передают объект со множеством полей, зависящих от компонента. Например, у v-data-table доступны:

  • item — объект данных текущей строки.
  • index — индекс элемента в массиве.
  • selected — булево значение, показывающее, выделена ли строка.
  • isExpanded — состояние раскрытой строки (если используется expandable row).

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

<v-data-table :items="users">
  <template v-slot:item="{ item, index, selected }">
    <tr :class="{ 'highlighted': selected }">
      <td>{{ index + 1 }}</td>
      <td>{{ item.name }}</td>
      <td>{{ item.email }}</td>
    </tr>
  </template>
</v-data-table>

Передача дополнительных данных через scoped slots

Scoped slots позволяют создавать полностью кастомные элементы, используя данные родительского компонента. Например, список карточек с динамическим контентом:

<v-card v-for="product in products" :key="product.id">
  <template v-slot:default="{ product }">
    <v-card-title>{{ product.title }}</v-card-title>
    <v-card-text>{{ product.description }}</v-card-text>
  </template>
</v-card>

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


Scoped slots с функциями

Vuetify поддерживает передачу функций через слоты, что позволяет управлять поведением компонента внутри слота. Пример с кнопкой действия в строке таблицы:

<v-data-table :items="tasks">
  <template v-slot:item.action="{ item }">
    <v-btn color="primary" @click="completeTask(item.id)">
      Завершить
    </v-btn>
  </template>
</v-data-table>

Здесь:

  • completeTask — метод родительского компонента.
  • item предоставляет доступ к уникальному идентификатору задачи.
  • Каждый слот получает индивидуальные данные, что позволяет создавать динамические кнопки и элементы управления.

Scoped slots для динамического списка

Scoped slots особенно полезны для компонентов с повторяющимися элементами, таких как v-list и v-data-table. Например, можно полностью контролировать отображение элементов списка:

<v-list :items="messages">
  <template v-slot:default="{ item, index }">
    <v-list-item :key="index">
      <v-list-item-content>
        <v-list-item-title>{{ item.sender }}</v-list-item-title>
        <v-list-item-subtitle>{{ item.text }}</v-list-item-subtitle>
      </v-list-item-content>
    </v-list-item>
  </template>
</v-list>

Преимущества такого подхода:

  • Полный контроль разметки.
  • Доступ к каждому элементу данных без необходимости модифицировать сам компонент.
  • Возможность добавления условной логики и динамических стилей на уровне слота.

Совместное использование scoped slots и событий

Scoped slots удобно сочетать с кастомными событиями. Например, таблица с возможностью редактирования строк:

<v-data-table :items="products">
  <template v-slot:item.edit="{ item }">
    <v-btn icon @click="$emit('edit-product', item)">
      <v-icon>mdi-pencil</v-icon>
    </v-btn>
  </template>
</v-data-table>

Преимущества:

  • Слот получает данные строки через item.
  • Родительский компонент может обрабатывать события (edit-product) с полным контекстом.

Использование нескольких scoped slots в одном компоненте

Vuetify позволяет одновременно использовать несколько слотов с разными контекстами. Пример для v-data-table:

<v-data-table :items="users">
  <template v-slot:item.name="{ item }">
    <strong>{{ item.name }}</strong>
  </template>

  <template v-slot:item.email="{ item }">
    <a :href="`mailto:${item.email}`">{{ item.email }}</a>
  </template>

  <template v-slot:item.role="{ item }">
    <v-chip>{{ item.role }}</v-chip>
  </template>
</v-data-table>

Каждый слот получает одинаковый контекст (item), но позволяет разделить логику и стили для разных колонок.


Полезные паттерны

  1. Expandable rows: комбинирование v-slot:expanded-item с item для создания раскрывающихся деталей.
  2. Custom headers: v-slot:header для управления заголовками таблицы.
  3. Dynamic actions: v-slot:item.action для кнопок управления каждой записью.
  4. Conditional rendering: использование v-if внутри слота для изменения контента в зависимости от состояния.

Советы по оптимизации

  • Использовать деструктуризацию слота для улучшения читаемости кода.
  • Ограничить логику внутри слота до визуального отображения, а бизнес-логику держать в методах родителя.
  • Применять computed свойства для подготовки данных перед передачей в слот.
  • Для сложных компонентов создавать отдельные функциональные компоненты и использовать их внутри scoped slots.

Scoped slots в Vuetify — это мощный инструмент, который превращает компоненты в гибкие и переиспользуемые элементы интерфейса, позволяя полностью контролировать их разметку, стили и поведение без изменения исходного компонента.