Действия: обработка событий и пользовательских взаимодействий

Stimulus строится на концепции контроллеров, связывающих поведение JavaScript с HTML-элементами. Основной инструмент для обработки событий и взаимодействия пользователя в Stimulus — это действия (actions). Они позволяют напрямую привязывать события DOM к методам контроллера, что делает код лаконичным, модульным и легко поддерживаемым.


Основы действий

Действие в Stimulus определяется с помощью атрибута data-action. Формат записи:

<button data-action="событие#метод">Нажми меня</button>
  • событие — любое стандартное событие DOM (например, click, input, submit).
  • метод — метод контроллера, который будет вызван при наступлении события.
  • # — разделитель между событием и методом.

Пример:

<div data-controller="hello">
  <button data-action="click#greet">Приветствие</button>
</div>
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  greet(event) {
    console.log("Привет, Stimulus!");
  }
}

При клике на кнопку вызывается метод greet.


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

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

<button data-action="click#greet mouseover#highlight">Кнопка</button>

В этом примере:

  • click#greet вызывает метод greet при клике;
  • mouseover#highlight вызывает метод highlight при наведении мыши.

Порядок действий в атрибуте не имеет значения — все события обрабатываются независимо.


Параметры событий и контекст

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

greet(event) {
  console.log(event.target); // элемент, вызвавший событие
  console.log(event.type);   // тип события
}

Важно: this внутри метода действия ссылается на текущий экземпляр контроллера, что позволяет обращаться к this.element или другим методам контроллера без потери контекста.


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

Stimulus поддерживает модификаторы событий, упрощающие работу с распространёнными задачами:

  • once — обработчик срабатывает один раз;
  • prevent — вызывает event.preventDefault();
  • stop — вызывает event.stopPropagation().

Примеры:

<form data-controller="form" data-action="submit->form#send prevent">
  <input type="text">
  <button type="submit">Отправить</button>
</form>

Метод send будет вызван при отправке формы, но стандартное поведение формы (перезагрузка страницы) будет предотвращено.

<button data-action="click->notifications#show once">Показать уведомление</button>

Метод show вызовется только один раз при первом клике.


Делегирование событий

Stimulus позволяет использовать делегирование событий через CSS-селекторы, облегчая работу с динамически создаваемыми элементами:

<ul data-controller="list" data-action="click->list#selectItem">
  <li data-list-target="item">Элемент 1</li>
  <li data-list-target="item">Элемент 2</li>
</ul>
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["item"]

  selectItem(event) {
    const clickedItem = event.target.closest("[data-list-target='item']")
    if (!clickedItem) return
    clickedItem.classList.toggle("selected")
  }
}

Метод selectItem будет работать даже при добавлении новых <li> элементов динамически, так как событие делегировано родительскому элементу <ul>.


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

Stimulus позволяет связывать действия с пользовательскими событиями, создаваемыми через dispatch:

this.element.dispatchEvent(
  new CustomEvent("item:selected", { detail: { id: 42 }, bubbles: true })
)

Привязка действия к пользовательскому событию:

<div data-controller="items" data-action="item:selected->items#handleSelection"></div>

Метод контроллера получит объект события с доступом к event.detail:

handleSelection(event) {
  console.log(event.detail.id) // 42
}

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

  • модульность;
  • лёгкая интеграция между разными контроллерами;
  • поддержка событий с передачей данных.

События клавиатуры и модификаторы клавиш

Stimulus поддерживает специфичные модификаторы для клавиш:

<input data-action="keydown.enter->search#submit keydown.esc->search#clear">
  • keydown.enter — срабатывает только при нажатии клавиши Enter.
  • keydown.esc — срабатывает только при нажатии Escape.

Можно комбинировать модификаторы с prevent и stop:

<input data-action="keydown.enter->search#submit prevent">

Это предотвращает стандартное поведение формы при нажатии Enter и вызывает метод submit.


Асинхронные действия и взаимодействия

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

async loadData(event) {
  event.preventDefault()
  const response = await fetch("/data.json")
  const data = await response.json()
  console.log(data)
}

Привязка:

<button data-action="click->data#loadData">Загрузить данные</button>

Лучшие практики работы с действиями

  • Действия должны оставаться короткими и специализированными, метод контроллера лучше ограничить одной конкретной задачей.
  • Использовать делегирование событий для списков и динамических элементов.
  • Предпочтительно применять модификаторы событий, вместо ручного вызова preventDefault() и stopPropagation().
  • Пользовательские события делают контроллеры более модульными и взаимосвязанными, уменьшая жесткую зависимость между элементами.

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