Множественные слоты

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

Основы работы с множественными слотами

Множественные слоты в Stencil позволяют компоненту принимать несколько фрагментов контента и распределять их в разные части шаблона. Каждый слот можно назначить уникальное имя, что позволяет управлять тем, какой контент куда попадет.

В HTML используется стандартный элемент <slot>, а в Stencil можно добавить атрибут name, чтобы различать слоты. Когда контент передается в компонент, каждый слот будет соответствовать своему назначению.

Пример простого компонента с двумя слотами:

@Component({
  tag: 'app-multi-slot',
  styleUrl: 'app-multi-slot.css',
  shadow: true
})
export class AppMultiSlot {

  render() {
    return (
      <div>
        <header>
          <slot name="header-content"></slot>
        </header>
        <main>
          <slot name="main-content"></slot>
        </main>
      </div>
    );
  }
}

В данном примере компонент app-multi-slot содержит два слота — один для содержимого заголовка и второй для основного контента. Они имеют уникальные имена, которые позволяют различать контент, передаваемый в каждый слот.

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

Имена слотов важны, так как они позволяют точно указать, какой контент должен попасть в какой слот. Когда компонент с несколькими слотами используется в другом компоненте или в приложении, контент можно передавать по именам, как показано в следующем примере:

<app-multi-slot>
  <div slot="header-content">
    <h1>Заголовок страницы</h1>
  </div>
  <div slot="main-content">
    <p>Основное содержание страницы.</p>
  </div>
</app-multi-slot>

Здесь, используя атрибут slot, каждый блок контента попадает в нужный слот компонента app-multi-slot. Важно, что если имя слота не будет совпадать с именем, переданным в компоненте, то этот контент не будет отображен.

Слот по умолчанию

Stencil также поддерживает слот по умолчанию, который используется, если контент не был передан в слот с конкретным именем. Для этого необходимо просто использовать слот без атрибута name. Например:

@Component({
  tag: 'app-default-slot',
  styleUrl: 'app-default-slot.css',
  shadow: true
})
export class AppDefaultSlot {

  render() {
    return (
      <div>
        <slot></slot>  <!-- Слот по умолчанию -->
      </div>
    );
  }
}

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

Для реализации слота по умолчанию в случае с множественными слотами можно комбинировать именованные и неименованные слоты, чтобы обеспечить гибкость в размещении контента:

@Component({
  tag: 'app-multi-slot-with-default',
  styleUrl: 'app-multi-slot-with-default.css',
  shadow: true
})
export class AppMultiSlotWithDefault {

  render() {
    return (
      <div>
        <header>
          <slot name="header-content"></slot>
        </header>
        <main>
          <slot name="main-content"></slot>
          <slot></slot>  <!-- Слот по умолчанию -->
        </main>
      </div>
    );
  }
}

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

Распределение контента через несколько слотов

Одним из ключевых преимуществ множественных слотов является возможность детально распределять контент внутри компонента. Это особенно полезно в сложных интерфейсах, где необходимо отображать различные части контента в разных местах. Например, можно создать карточку с несколькими секциями:

@Component({
  tag: 'app-card',
  styleUrl: 'app-card.css',
  shadow: true
})
export class AppCard {

  render() {
    return (
      <div class="card">
        <header>
          <slot name="title"></slot>
        </header>
        <section>
          <slot name="content"></slot>
        </section>
        <footer>
          <slot name="footer"></slot>
        </footer>
      </div>
    );
  }
}

В этом примере компонент app-card содержит три различных слота: для заголовка, основного контента и подвала. Каждое из этих мест может быть заполнено контентом, переданным в компонент:

<app-card>
  <div slot="title">Заголовок карточки</div>
  <div slot="content">Основное содержание карточки</div>
  <div slot="footer">Подвал карточки</div>
</app-card>

Управление содержимым с помощью слотов

Множественные слоты предоставляют большую гибкость для управления содержимым компонента. Например, можно задать значение по умолчанию для каждого из слотов с помощью атрибута fallback, чтобы компонент мог адаптироваться в зависимости от того, был ли передан контент.

@Component({
  tag: 'app-fallback-slot',
  styleUrl: 'app-fallback-slot.css',
  shadow: true
})
export class AppFallbackSlot {

  render() {
    return (
      <div>
        <header>
          <slot name="header-content">По умолчанию: Заголовок</slot>
        </header>
        <main>
          <slot name="main-content">По умолчанию: Основной контент</slot>
        </main>
      </div>
    );
  }
}

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

Заключение

Множественные слоты в Stencil открывают широкий спектр возможностей для разработки компонентов с гибким распределением контента. Использование именованных и неименованных слотов позволяет создавать переиспользуемые компоненты, которые можно легко адаптировать под различные сценарии. Механизм fallback контента помогает улучшить UX, предоставляя стандартное содержимое, если пользователь не передал свои данные.