Пользовательские события

FAST Element предоставляет мощный механизм работы с пользовательскими событиями, позволяя компонентам взаимодействовать друг с другом и с внешним окружением через настраиваемые события. Пользовательские события — это объекты типа CustomEvent, которые могут передавать данные, конфигурировать поведение всплытия и быть подписаны с использованием стандартных DOM-методов.


Создание и инициализация событий

Для генерации пользовательского события используется конструктор CustomEvent:

const event = new CustomEvent('имя_события', {
    detail: { ключ: 'значение' },
    bubbles: true,
    composed: true
});

Параметры:

  • detail — объект, содержащий произвольные данные, передаваемые подписчикам события.
  • bubbles — логическое значение, определяющее, будет ли событие всплывать по DOM-дереву.
  • composed — разрешает событию пройти через Shadow DOM границы.

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


Генерация событий внутри FAST Element

FAST Element предоставляет метод this.$emit для удобного создания и отправки событий:

import { FASTElement } from "@microsoft/fast-element";

class MyElement extends FASTElement {
    triggerCustomEvent() {
        this.$emit('my-event', { message: 'Hello, FAST!' });
    }
}

Метод $emit автоматически формирует объект CustomEvent с переданным именем события и данными detail. По умолчанию событие всплывающее и составное, что упрощает интеграцию с другими компонентами и родительским DOM.


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

Подписка может выполняться двумя способами: через стандартный DOM API (addEventListener) и через шаблон FAST с помощью директивы @event.

Через addEventListener:

const element = document.querySelector('my-element');
element.addEventListener('my-event', (e) => {
    console.log(e.detail.message);
});

Через шаблон FAST:

import { html } from "@microsoft/fast-element";

const template = html<MyElement>`
    <button @click="${x => x.triggerCustomEvent()}">Click me</button>
    <my-element @my-event="${(x, c) => console.log(c.event.detail.message)}"></my-element>
`;

Директива @event позволяет связывать событие с обработчиком прямо в шаблоне, что упрощает реактивное программирование в компонентах.


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

  • Инкапсуляция логики: компонент сам генерирует события без необходимости напрямую манипулировать родительским DOM.
  • Обмен данными: через detail можно передавать любые объекты, массивы или примитивные значения.
  • Совместимость с Shadow DOM: использование composed: true позволяет событиям проникать за границы Shadow DOM, не нарушая инкапсуляцию стилей и структуры.
  • Стандартизация: события полностью соответствуют спецификации DOM, что обеспечивает совместимость с другими библиотеками и нативными обработчиками.

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

  1. Компонент уведомления
class NotificationElement extends FASTElement {
    notify(message) {
        this.$emit('notify', { message });
    }
}

Родительский элемент может подписаться на событие notify и отобразить уведомление:

notificationElement.addEventListener('notify', (e) => {
    alert(e.detail.message);
});
  1. Двусторонняя коммуникация между компонентами

Компонент A отправляет событие, компонент B реагирует на него и инициирует ответное событие:

// В компоненте A
this.$emit('request-update', { data: 42 });

// В компоненте B
elementB.addEventListener('request-update', (e) => {
    console.log(e.detail.data);
    elementB.$emit('update-response', { status: 'ok' });
});
  1. События формы и валидации

Форма может генерировать событие при изменении данных, а родительская логика — подписываться на него для проверки или сохранения:

this.$emit('form-changed', { fields: this.fields });

Рекомендации по проектированию событий

  • Выбирать информативные имена событий, отражающие их семантику (user-logged-in, item-selected).
  • Минимизировать использование глобальных событий; предпочтение отдавать компонентному взаимодействию.
  • Сохранять события тонкими и простыми, передавая только необходимые данные в detail.
  • При необходимости обработки ошибки или отмены действия использовать CustomEvent с cancelable: true и проверять event.defaultPrevented.

Расширенные возможности

  • Типизация данных: в TypeScript можно типизировать detail для безопасного использования:
interface MyEventDetail {
    message: string;
}

this.$emit<MyEventDetail>('my-event', { message: 'Typed event' });
  • Отмена события: с cancelable: true событие может быть отменено обработчиком с помощью event.preventDefault().
  • Композиция событий: один компонент может агрегировать несколько внутренних событий в одно внешнее, облегчая реактивную архитектуру.

Пользовательские события в FAST Element являются фундаментальным инструментом построения реактивных и инкапсулированных компонентов, позволяя управлять взаимодействием без нарушения принципов Shadow DOM и обеспечивая гибкость передачи данных между элементами.