Stimulus — это легковесный JavaScript-фреймворк, который ориентирован на улучшение работы с существующим HTML без необходимости полной виртуализации DOM. Основная идея заключается в минимальном вмешательстве в структуру документа: Stimulus не создаёт виртуальный DOM, а напрямую связывает поведение с элементами страницы через контроллеры и декларативные атрибуты.
Контроллеры Stimulus управляют конкретными участками DOM, что
позволяет изолировать логику и минимизировать взаимозависимости. Каждый
контроллер — это класс JavaScript, который расширяет базовый
Controller фреймворка.
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["output"]
connect() {
this.outputTarget.textContent = "Stimulus подключен!"
}
}
Здесь ключевые моменты:
static targets — определяет элементы внутри
контроллера, с которыми будет производиться взаимодействие.connect() — метод, который вызывается при инициализации
контроллера и привязке его к DOM.Stimulus использует атрибуты данных, чтобы связать HTML с контроллерами и их методами. Основные атрибуты:
data-controller — объявляет контроллер на
элементе.data-action — связывает события DOM с методами
контроллера.data-target — помечает элементы, с которыми контроллер
будет работать.Пример использования:
<div data-controller="greeting">
<input data-action="input->greeting#update" type="text">
<span data-greeting-target="output"></span>
</div>
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["output"]
update(event) {
this.outputTarget.textContent = `Привет, ${event.target.value}!`
}
}
В этом примере Stimulus напрямую управляет DOM, без промежуточного слоя виртуализации: изменение текста происходит на конкретном элементе, привязанном через target.
В Stimulus события обрабатываются через декларативные
data-action, что упрощает поддержку кода и уменьшает
необходимость в явном добавлении слушателей через
addEventListener. Формат атрибута:
data-action="событие->контроллер#метод"
Можно привязывать несколько событий к одному методу или использовать несколько методов для одного события:
<button data-action="click->counter#increment mouseover->counter#highlight">
Нажми меня
</button>
export default class extends Controller {
static targets = ["display"]
increment() {
this.displayTarget.textContent = parseInt(this.displayTarget.textContent) + 1
}
highlight() {
this.displayTarget.classList.add("highlight")
}
}
Stimulus позволяет логично управлять состоянием интерфейса без необходимости хранить ссылки на DOM вручную. Targets обеспечивают чёткую идентификацию элементов и предотвращают поломку логики при изменении структуры документа.
export default class extends Controller {
static targets = ["panel", "button"]
toggle() {
this.panelTarget.classList.toggle("hidden")
this.buttonTarget.textContent = this.panelTarget.classList.contains("hidden") ? "Показать" : "Скрыть"
}
}
Такой подход сохраняет код компактным и декларативным, избавляя от
необходимости писать громоздкие селекторы
querySelector.
Контроллеры Stimulus имеют несколько ключевых методов жизненного цикла:
connect() — вызывается при подключении контроллера к
DOM.disconnect() — вызывается при удалении элемента из
DOM.initialize() — вызывается один раз при создании
экземпляра контроллера.refresh() — позволяет вручную обновить состояние
контроллера при изменении DOM.Использование этих методов позволяет управлять ресурсами и состоянием элементов, например, добавлять или удалять слушатели событий в нужные моменты.
Stimulus предоставляет систему values, которая упрощает
хранение состояния без прямой работы с атрибутами DOM.
export default class extends Controller {
static values = { count: Number }
connect() {
console.log(this.countValue)
}
increment() {
this.countValue++
}
}
HTML:
<div data-controller="counter" data-counter-count-value="5">
<button data-action="click->counter#increment">Увеличить</button>
</div>
values позволяют синхронизировать данные между DOM и
контроллером автоматически, сохраняя реактивность без виртуализации.
Stimulus идеально подходит для управления асинхронными событиями, такими как AJAX-запросы или WebSocket-обновления. Изменения DOM происходят только там, где это нужно, без полной перерисовки страницы.
export default class extends Controller {
static targets = ["list"]
async fetchData() {
const response = await fetch("/api/items")
const items = await response.json()
this.listTarget.innerHTML = items.map(item => `<li>${item.name}</li>`).join("")
}
}
data-target и data-controller снижает
зависимость от классов и id.data-action
заменяет явное подключение слушателей через JS.Stimulus создаёт структуру, в которой DOM остаётся главным источником истины, а логика JavaScript добавляется поверх существующей разметки без виртуализации и сложных слоёв абстракции. Это делает фреймворк особенно подходящим для прогрессивного улучшения интерфейсов на уже существующих страницах.