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

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

Что такое динамические слоты

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

Принцип работы динамических слотов

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

Пример простого динамического слота

import { Component, h, Prop } from '@stencil/core';

@Component({
  tag: 'my-dynamic-slot',
  styleUrl: 'my-dynamic-slot.css',
  shadow: true,
})
export class MyDynamicSlot {
  @Prop() condition: boolean;

  render() {
    return (
      <div>
        {this.condition ? (
          <slot name="dynamic-content">Default content if condition is false</slot>
        ) : (
          <div>No dynamic content available</div>
        )}
      </div>
    );
  }
}

В данном примере компонент my-dynamic-slot использует слот, который в зависимости от значения пропа condition изменяет своё содержимое. Если условие выполняется, вставляется содержимое слота, в противном случае — отображается дефолтный текст.

Работа с несколькими слотами

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

import { Component, h } from '@stencil/core';

@Component({
  tag: 'multi-slot-component',
  styleUrl: 'multi-slot-component.css',
  shadow: true,
})
export class MultiSlotComponent {
  render() {
    return (
      <div>
        <slot name="header">Default header content</slot>
        <slot name="body">Default body content</slot>
        <slot name="footer">Default footer content</slot>
      </div>
    );
  }
}

В этом примере компонент имеет три слота: header, body и footer, каждый из которых можно заполнять различным содержимым. Динамическое управление каждым из этих слотов позволяет легко менять внешний вид компонента в зависимости от данных или условий.

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

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

Пример передачи данных через слот:

import { Component, h, State } from '@stencil/core';

@Component({
  tag: 'data-slot',
  styleUrl: 'data-slot.css',
  shadow: true,
})
export class DataSlot {
  @State() dynamicData: string = "Initial dynamic data";

  render() {
    return (
      <div>
        <slot name="data-slot">{this.dynamicData}</slot>
      </div>
    );
  }
}

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

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

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

import { Component, h, State } from '@stencil/core';

@Component({
  tag: 'event-driven-slot',
  styleUrl: 'event-driven-slot.css',
  shadow: true,
})
export class EventDrivenSlot {
  @State() slotContent: string = "Initial content";

  handleChange() {
    this.slotContent = "Updated content based on event";
  }

  render() {
    return (
      <div>
        <button onCl ick={() => this.handleChange()}>Change Slot Content</button>
        <slot>{this.slotContent}</slot>
      </div>
    );
  }
}

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

Рендеринг слота с условием

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

import { Component, h, Prop } from '@stencil/core';

@Component({
  tag: 'conditional-slot',
  styleUrl: 'conditional-slot.css',
  shadow: true,
})
export class ConditionalSlot {
  @Prop() isVisible: boolean;

  render() {
    return (
      <div>
        {this.isVisible ? (
          <slot>Conditional slot content</slot>
        ) : (
          <div>Slot content is hidden</div>
        )}
      </div>
    );
  }
}

В этом примере содержимое слота рендерится только если проп isVisible имеет значение true. В противном случае отображается другой элемент.

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

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

import { Component, h } from '@stencil/core';

@Component({
  tag: 'fragment-slot',
  styleUrl: 'fragment-slot.css',
  shadow: true,
})
export class FragmentSlot {
  render() {
    return (
      <div>
        <slot>
          <span>Fallback content</span>
        </slot>
      </div>
    );
  }
}

В данном примере компонент включает фрагмент — элемент <span>, который будет отображаться, если в слот не будет передано другое содержимое.

Заключение

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