Декоратор @Listen

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

Синтаксис использования декоратора @Listen

Декоратор @Listen используется для привязки обработчика событий к методу компонента. Основной синтаксис следующий:

@Listen('eventName', { target: 'window' })
eventHandler(event: Event) {
    // Обработчик события
}

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

Параметры декоратора

Декоратор @Listen принимает два обязательных параметра: имя события и объект с дополнительными опциями.

  • Имя события (eventName): строка, представляющая имя события, на которое компонент будет реагировать.

  • Опции: объект с конфигурацией для привязки обработчика. Основные опции:

    • target: указывает, на какой объект будет подписан обработчик. Возможные значения:

      • 'document' — для глобальных событий на уровне документа.
      • 'window' — для событий окна.
      • 'body' — для событий, происходящих в теле страницы.
      • 'element' — для событий внутри компонента.
    • capture: булевое значение, определяющее, должен ли обработчик события срабатывать на фазе захвата (по умолчанию false).

    • passive: если установлено в true, обработчик не будет блокировать прокрутку страницы.

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

Слушаем событие внутри компонента

@Component({
  tag: 'my-component',
  styleUrl: 'my-component.css',
  shadow: true
})
export class MyComponent {

  @Listen('click')
  handleClick(event: MouseEvent) {
    console.log('Element clicked:', event.target);
  }

}

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

Слушаем глобальные события

@Component({
  tag: 'my-component',
  styleUrl: 'my-component.css',
  shadow: true
})
export class MyComponent {

  @Listen('resize', { target: 'window' })
  handleResize(event: Event) {
    console.log('Window resized', event);
  }

}

Здесь обработчик события handleResize будет реагировать на изменения размера окна.

Особенности работы с событиями

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

  2. Удаление обработчиков: Когда компонент уничтожается, все подписки на события автоматически отменяются. Это позволяет избежать утечек памяти, не требуя вручную отсоединять обработчики.

  3. Типы событий: обработчики могут принимать аргумент события, который соответствует типу события, на которое подписан компонент. Например, для события click это будет MouseEvent, а для события resizeEvent.

  4. Множественные обработчики: можно использовать несколько декораторов @Listen в одном компоненте, чтобы слушать различные события. Каждый декоратор будет связывать свой метод с определенным событием.

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

Использование декоратора с кастомными событиями

Stencil поддерживает как нативные DOM-события, так и собственные (кастомные) события. В случае с кастомными событиями можно использовать тот же декоратор @Listen, но с событием, которое было создано в другом компоненте.

Пример создания кастомного события:

@Component({
  tag: 'child-component',
  styleUrl: 'child-component.css',
  shadow: true
})
export class ChildComponent {

  @Event() customEvent: EventEmitter<string>;

  triggerEvent() {
    this.customEvent.emit('Hello from child!');
  }

}

И теперь можно прослушивать это событие в родительском компоненте:

@Component({
  tag: 'parent-component',
  styleUrl: 'parent-component.css',
  shadow: true
})
export class ParentComponent {

  @Listen('customEvent')
  handleCustomEvent(event: CustomEvent) {
    console.log('Received custom event:', event.detail);
  }

}

В этом случае метод handleCustomEvent сработает, когда будет выброшено событие customEvent из дочернего компонента.

Ограничения и рекомендации

  • Работа с нативными и кастомными событиями: для работы с кастомными событиями важно, чтобы событие было выброшено в контексте DOM-дерева, которое может быть отслежено. Если событие не относится к DOM, оно не будет перехвачено с помощью декоратора @Listen.

  • Оптимизация производительности: при подписке на глобальные события, такие как scroll или resize, следует учитывать возможное влияние на производительность, особенно если обработчики выполняют сложные операции. В таких случаях рекомендуется использовать дебаунсинг или лимитирование частоты срабатывания.

  • Работа с компонентами Shadow DOM: Stencil поддерживает Shadow DOM, и это влияет на то, как события распространяются. События, сгенерированные внутри shadow-дерева компонента, не будут по умолчанию всплывать в родительский элемент за пределы компонента. Однако можно настроить всплытие событий с помощью опции bubbles при создании события.

Заключение

Декоратор @Listen является мощным инструментом для работы с событиями в Stencil, позволяя слушать как нативные события DOM, так и кастомные события внутри компонента. Это решение облегчает процесс подписки на события и управление ими в рамках компонентов и их иерархий, обеспечивая высокую гибкость и масштабируемость для создания сложных веб-приложений.