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

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

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

Пользовательские события (custom events) позволяют компонентам взаимодействовать друг с другом без жёсткой зависимости. В стандартном JavaScript пользовательское событие создаётся с помощью конструктора CustomEvent:

const event = new CustomEvent("custom:action", {
  detail: { message: "Пример пользовательского события" },
  bubbles: true
});
element.dispatchEvent(event);
  • type — имя события, которое может содержать двоеточие для пространственного разделения (custom:action).
  • detail — объект с данными, передаваемыми слушателю события.
  • bubbles — логический флаг, указывающий, должно ли событие всплывать через DOM.

В Stimulus взаимодействие с пользовательскими событиями становится более декларативным.

Объявление действий в контроллере

В контроллерах Stimulus действия объявляются через атрибут data-action. Для пользовательских событий используется следующий синтаксис:

<div data-controller="example" data-action="custom:action->example#handleCustomEvent"></div>
  • custom:action — имя события.
  • example#handleCustomEvent — метод контроллера, который будет вызван при срабатывании события.

Метод контроллера принимает объект события в качестве аргумента, что позволяет работать с переданными данными:

import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  handleCustomEvent(event) {
    console.log(event.detail.message); // "Пример пользовательского события"
  }
}

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

Контроллер Stimulus может сам создавать и отправлять пользовательские события. Для этого используется dispatch метод, встроенный в базовый класс Controller:

this.dispatch("action", { detail: { message: "Событие отправлено" }, bubbles: true });
  • Первый аргумент — имя события, без префикса контроллера.
  • Второй аргумент — объект с detail и другими свойствами события.

Событие автоматически получает префикс контроллера, например, example:action, если контроллер называется example.

Поддержка всплытия и делегирования

Stimulus полностью поддерживает стандартное поведение событий:

  • Всплытие (bubbles) позволяет ловить события на родительских элементах.
  • Делегирование достигается указанием обработчика на родительском элементе, что особенно полезно для динамически создаваемых элементов.
<div data-controller="parent" data-action="example:action->parent#onChildAction">
  <div data-controller="example"></div>
</div>

В этом примере событие example:action всплывёт до родителя и будет обработано методом onChildAction.

Передача данных через события

detail позволяет передавать любые данные от источника события к слушателю. Например:

this.dispatch("update", { detail: { id: 42, status: "ready" } });

В обработчике:

updateHandler(event) {
  const { id, status } = event.detail;
  console.log(`Обновление элемента ${id} со статусом ${status}`);
}

Такой подход обеспечивает слабую связанность компонентов и улучшает масштабируемость приложения.

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

Иногда события должны обрабатываться вне структуры контроллера. Для этого можно использовать window.addEventListener или document.addEventListener:

window.addEventListener("example:global", event => {
  console.log(event.detail.message);
});

При этом контроллер может инициировать глобальное событие:

this.dispatch("global", { detail: { message: "Глобальное событие" }, target: window });

Использование target позволяет направлять событие на любой элемент, включая window и document.

Советы по именованию событий

  • Разделение через двоеточие (controller:event) помогает избегать конфликтов между событиями разных контроллеров.
  • Использование глаголов в именах (update, submit, toggle) повышает читаемость кода.
  • Для событий с ограниченной областью можно использовать короткие имена (action, change), при этом контроллер задаёт контекст.

Обработка множественных событий

Stimulus позволяет указывать несколько событий для одного метода:

<div data-controller="example" data-action="custom:start->example#start custom:stop->example#stop"></div>

Методы start и stop будут вызваны при соответствующих событиях, что упрощает обработку сложного поведения компонентов.

Работа с асинхронными событиями

События могут инициировать асинхронные процессы:

async handleCustomEvent(event) {
  const response = await fetch(`/api/data/${event.detail.id}`);
  const data = await response.json();
  this.element.textContent = data.name;
}

Stimulus корректно поддерживает асинхронные обработчики, что позволяет интегрировать события с современными API без дополнительного обёртывания.

Практические сценарии

  1. Формы и валидация — отправка событий при изменении полей формы для централизованной обработки.
  2. Модальные окна — уведомление других компонентов о закрытии/открытии окна.
  3. Списки и фильтры — изменение состояния фильтра и обновление других элементов через пользовательские события.

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