Stimulus — это фреймворк для улучшения HTML с помощью легковесной привязки поведения к элементам страницы. В основе работы лежат контроллеры, которые связывают DOM-элементы с методами JavaScript, позволяя управлять событиями и состоянием приложения без перегрузки сложной архитектурой.
Контроллеры в Stimulus регистрируются через data-controller, а методы, обрабатывающие события, — через data-action. Пример базовой привязки:
<div data-controller="example">
<button data-action="click->example#greet">Сказать привет</button>
</div>
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
greet() {
console.log("Привет!")
}
}
События DOM в Stimulus могут быть локальными и глобальными. Локальные события обрабатываются внутри одного контроллера. Например, клик на кнопку вызывает метод контроллера, как показано выше.
Для глобальных событий, которые могут затрагивать несколько контроллеров, используется механизм CustomEvent и window.dispatchEvent. Это позволяет синхронизировать состояние между разными частями приложения без сложной архитектуры.
Пример глобального события:
// Отправка события
window.dispatchEvent(new CustomEvent("user:logged_in", {
detail: { username: "ivan" }
}));
// Подписка в другом контроллере
export default class extends Controller {
connect() {
window.addEventListener("user:logged_in", this.handleLogin)
}
disconnect() {
window.removeEventListener("user:logged_in", this.handleLogin)
}
handleLogin = (event) => {
console.log("Пользователь вошёл:", event.detail.username)
}
}
Использование CustomEvent позволяет отделить логику компонентов и избегать жёсткой зависимости между контроллерами.
Stimulus не предоставляет встроенного глобального хранилища, но можно реализовать простую централизованную модель. Обычно создаётся объект store, который хранит текущее состояние приложения. Контроллеры подписываются на изменения состояния через события.
Пример структуры простого store:
const store = {
state: {
user: null,
theme: "light"
},
subscribers: [],
subscribe(callback) {
this.subscribers.push(callback)
},
setState(newState) {
this.state = { ...this.state, ...newState }
this.subscribers.forEach(callback => callback(this.state))
}
}
export default store
Контроллеры используют store следующим образом:
import { Controller } from "@hotwired/stimulus"
import store from "./store"
export default class extends Controller {
connect() {
store.subscribe(this.updateView)
}
updateView = (state) => {
this.element.textContent = state.user ? `Привет, ${state.user}` : "Гость"
}
loginUser() {
store.setState({ user: "ivan" })
}
}
Контроллеры имеют методы жизненного цикла:
connect() — вызывается при подключении контроллера к
DOM.disconnect() — вызывается при удалении контроллера с
DOM.initialize() — вызывается один раз при создании
экземпляра контроллера.Эти методы позволяют управлять подписками на события, очищать таймеры и поддерживать консистентное состояние.
Пример безопасного управления событиями:
export default class extends Controller {
connect() {
window.addEventListener("theme:changed", this.updateTheme)
}
disconnect() {
window.removeEventListener("theme:changed", this.updateTheme)
}
updateTheme = (event) => {
document.body.dataset.theme = event.detail.theme
}
}
Stimulus позволяет создавать модульные, масштабируемые приложения, где управление событиями и глобальное состояние остаются простыми и прозрачными. Такой подход обеспечивает стабильность, удобство поддержки и низкий порог вхождения для расширения функциональности.