@Event для пользовательских событий

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

Создание пользовательских событий

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

Применение декоратора @Event выглядит следующим образом:

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

@Component({
  tag: 'my-button',
  styleUrl: 'my-button.css',
  shadow: true
})
export class MyButton {
  @Event() buttonClicked: EventEmitter<void>;

  handleClick() {
    this.buttonClicked.emit();
  }

  render() {
    return (
      <button onCl ick={() => this.handleClick()}>Click me!</button>
    );
  }
}

В этом примере компонент my-button создает событие buttonClicked с помощью декоратора @Event. Метод handleClick вызывает emit() для отправки этого события. Это событие теперь может быть перехвачено родительским компонентом.

Детали события

Каждое событие, создаваемое с помощью @Event, является экземпляром EventEmitter. Этот объект предоставляет методы для эмитации событий и их подписки. Кроме того, EventEmitter поддерживает передачу данных вместе с событием, что позволяет отправлять дополнительные параметры при его возникновении.

Пример с передачей данных:

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

@Component({
  tag: 'my-button',
  styleUrl: 'my-button.css',
  shadow: true
})
export class MyButton {
  @Event() buttonClicked: EventEmitter<string>;

  handleClick() {
    this.buttonClicked.emit('Hello from my-button!');
  }

  render() {
    return (
      <button onCl ick={() => this.handleClick()}>Click me!</button>
    );
  }
}

В этом случае событие buttonClicked будет отправлять строку с сообщением при каждом клике.

Прослушивание пользовательских событий

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

Пример компонента-родителя, который прослушивает событие buttonClicked от дочернего компонента:

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

@Component({
  tag: 'parent-component',
  styleUrl: 'parent-component.css',
  shadow: true
})
export class ParentComponent {
  handleButtonClick(event: CustomEvent<string>) {
    console.log(event.detail); // 'Hello from my-button!'
  }

  render() {
    return (
      <my-button onButtonClic ked={event => this.handleButtonClick(event)}></my-button>
    );
  }
}

Здесь компонент parent-component прослушивает событие buttonClicked, получая данные, передаваемые дочерним компонентом. С помощью события onButtonClicked можно привязать обработчик события, который будет вызван при его возникновении.

Детали события в CustomEvent

Поскольку Stencil использует стандартный механизм событий браузера, пользовательские события, созданные через @Event, являются экземплярами CustomEvent. Это означает, что в обработчике события можно получить доступ к объекту detail, в котором содержится дополнительная информация, переданная вместе с событием. Это может быть строка, объект или даже массив, в зависимости от того, что было передано в метод emit.

Пример передачи объекта:

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

@Component({
  tag: 'my-button',
  styleUrl: 'my-button.css',
  shadow: true
})
export class MyButton {
  @Event() buttonClicked: EventEmitter<object>;

  handleClick() {
    this.buttonClicked.emit({ message: 'Data sent from button!' });
  }

  render() {
    return (
      <button onCl ick={() => this.handleClick()}>Click me!</button>
    );
  }
}

В этом примере событие отправляет объект с полем message. Родительский компонент может получить доступ к этому объекту через event.detail.

Важные особенности

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

  2. Работа с асинхронными событиями: События могут быть использованы для асинхронных операций. Например, при отправке данных на сервер или обработке крупных вычислений можно отправлять промежуточные события, которые будут уведомлять другие компоненты о ходе выполнения.

  3. Модификаторы событий: В Stencil поддерживаются стандартные модификаторы событий, такие как bubbles, cancelable и другие. Эти параметры могут быть заданы при создании события, определяя его поведение при всплытии или отмене.

Пример с модификаторами:

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

@Component({
  tag: 'my-button',
  styleUrl: 'my-button.css',
  shadow: true
})
export class MyButton {
  @Event({
    bubbles: true,
    cancelable: true
  }) buttonClicked: EventEmitter<void>;

  handleClick() {
    this.buttonClicked.emit();
  }

  render() {
    return (
      <button onCl ick={() => this.handleClick()}>Click me!</button>
    );
  }
}

В этом примере событие buttonClicked будет всплывать по дереву DOM и его можно будет отменить, если это необходимо.

Заключение

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