← Назад к вопросам

Для чего нужен именованный slot?

2.3 Middle🔥 71 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Для чего нужен именованный slot?

Именованный slot — это функция веб-компонентов (Web Components), которая позволяет дочернему компоненту указать несколько мест (именованные слоты) где может быть размещено содержимое из родительского компонента.

Основная идея

Slots позволяют создавать компоненты-обёртки, которые оставляют "отверстия" для пользовательского контента. Это похоже на концепцию children в React, но мощнее.

Анонимный слот vs Именованный слот

Анонимный слот (по умолчанию)

<!-- Компонент -->
<template id="my-card">
  <style>
    .card { border: 1px solid #ccc; padding: 20px; }
  </style>
  <div class="card">
    <slot></slot>  <!-- Безымянный слот -->
  </div>
</template>

<!-- Использование -->
<my-card>
  <p>Это содержимое попадёт в безымянный слот</p>
</my-card>

Именованные слоты (named slots)

<!-- Компонент -->
<template id="layout-template">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot name="content"></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</template>

<!-- Использование -->
<my-layout>
  <h1 slot="header">Заголовок страницы</h1>
  <p slot="content">Основной контент</p>
  <small slot="footer">Копирайт 2024</small>
</my-layout>

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

class MyCard extends HTMLElement {
  constructor() {
    super();
    const template = document.querySelector('#card-template');
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.appendChild(template.content.cloneNode(true));
  }
}

customElements.define('my-card', MyCard);
<template id="card-template">
  <style>
    :host { display: block; border: 1px solid #ddd; padding: 16px; }
    .header { font-weight: bold; margin-bottom: 8px; }
    .footer { font-size: 12px; color: #666; margin-top: 8px; }
  </style>
  <div class="header">
    <slot name="title">Без заголовка</slot>
  </div>
  <div class="content">
    <slot></slot>
  </div>
  <div class="footer">
    <slot name="footer"></slot>
  </div>
</template>

<!-- Использование -->
<my-card>
  <div slot="title">Карточка продукта</div>
  <p>Описание продукта здесь</p>
  <small slot="footer">ID: 12345</small>
</my-card>

Именованные слоты в контексте фреймворков

Хотя React не использует нативные слоты (использует props для содержимого), похожую концепцию можно реализовать.

React (нативные слоты через Web Components)

// Web Component с именованными слотами
class Modal extends HTMLElement {
  connectedCallback() {
    this.innerHTML = `
      <div class="modal-overlay">
        <div class="modal-content">
          <div class="modal-header">
            <slot name="header"></slot>
          </div>
          <div class="modal-body">
            <slot name="body"></slot>
          </div>
          <div class="modal-footer">
            <slot name="footer"></slot>
          </div>
        </div>
      </div>
    `;
  }
}

customElements.define('my-modal', Modal);

// Использование в React
export function MyModalWrapper() {
  return (
    <my-modal>
      <h2 slot="header">Подтверждение</h2>
      <p slot="body">Вы уверены?</p>
      <div slot="footer">
        <button>Да</button>
        <button>Нет</button>
      </div>
    </my-modal>
  );
}

Vue (встроенная поддержка слотов)

<!-- Компонент CardComponent.vue -->
<template>
  <div class="card">
    <header class="card-header">
      <slot name="header">Без заголовка</slot>
    </header>
    <main class="card-body">
      <slot>Без содержимого</slot>
    </main>
    <footer class="card-footer">
      <slot name="footer"></slot>
    </footer>
  </div>
</template>

<style scoped>
.card { border: 1px solid #ddd; padding: 16px; }
.card-header { font-weight: bold; margin-bottom: 12px; }
.card-footer { font-size: 12px; margin-top: 12px; }
</style>

<!-- Использование -->
<CardComponent>
  <template #header>
    <h2>Карточка</h2>
  </template>
  
  <p>Содержимое здесь</p>
  
  <template #footer>
    <button>OK</button>
  </template>
</CardComponent>

Практические примеры использования

1. Layout компонент

<layout-component>
  <nav slot="sidebar">Меню</nav>
  <main slot="content">Содержимое</main>
  <footer slot="footer">Footer</footer>
</layout-component>

2. Dialog / Modal

<dialog-component>
  <h2 slot="title">Удалить элемент?</h2>
  <p slot="message">Это действие необратимо</p>
  <div slot="actions">
    <button>Отмена</button>
    <button>Удалить</button>
  </div>
</dialog-component>

3. Таблица с кастомными колонками

<data-table slot="columns">
  <column-header slot="name">Имя</column-header>
  <column-header slot="email">Email</column-header>
  <column-template slot="actions">
    <button>Редактировать</button>
  </column-template>
</data-table>

4. Карточка с разными частями

function ProductCard() {
  return (
    <product-card>
      <img slot="image" src="product.jpg" alt="Product" />
      <h3 slot="title">Название продукта</h3>
      <p slot="description">Описание</p>
      <div slot="price">$99.99</div>
      <button slot="action">В корзину</button>
    </product-card>
  );
}

Преимущества именованных слотов

  1. Гибкость — родитель может размещать контент в разных местах компонента
  2. Структурность — ясное разделение ответственности между слотами
  3. Переиспользуемость — один компонент может принимать разное содержимое
  4. Инкапсуляция — стили компонента не влияют на содержимое слота
  5. Семантичность — явно указываем, какой контент где размещается

Fallback содержимое

<template id="card">
  <div class="card-body">
    <slot name="content">Содержимое не предоставлено</slot>
  </div>
</template>

<!-- Если не указать содержимое, покажется fallback -->
<my-card></my-card> <!-- Покажет "Содержимое не предоставлено" -->

Доступ к слотам через JavaScript

class MyComponent extends HTMLElement {
  connectedCallback() {
    // Получить все элементы, назначенные слоту
    const slot = this.shadowRoot.querySelector('slot[name="header"]');
    const assignedElements = slot.assignedElements();
    
    console.log('Элементы в слоте header:', assignedElements);
  }
}

Заключение

Именованные слоты — это мощный механизм для создания гибких, переиспользуемых компонентов. Они особенно полезны в Web Components, но концепция также применяется во фреймворках через props и специальные синтаксисы (как Vue slots или React render props).

Для чего нужен именованный slot? | PrepBro