Stimulus строит интерфейс вокруг контроллеров,
которые привязываются к элементам DOM через атрибуты
data-controller. Контроллеры могут содержать
состояние, методы,
события и связи с другими
контроллерами. Иерархия контроллеров становится критически
важной при создании сложных интерфейсов с множеством взаимодействующих
компонентов.
В Stimulus контроллеры могут взаимодействовать между собой через контроллерные связи. Один элемент может быть родительским для нескольких дочерних контроллеров, что позволяет строить структурированную архитектуру компонентов.
<div data-controller="parent">
<div data-controller="child" data-child-target="item"></div>
<div data-controller="child" data-child-target="item"></div>
</div>
В этом примере parent является родителем для двух
дочерних контроллеров child.
Stimulus предлагает targets и values как основной механизм управления вложенными контроллерами:
Пример использования Targets для взаимодействия родителя и дочернего контроллера:
// parent_controller.js
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static targets = ["item"];
connect() {
console.log(`Найдено ${this.itemTargets.length} дочерних элемента`);
}
highlightItems() {
this.itemTargets.forEach(item => item.classList.add("highlight"));
}
}
// child_controller.js
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static targets = ["item"];
connect() {
console.log("Child подключен");
}
}
Stimulus позволяет дочернему контроллеру получать доступ к родительскому через встроенные API:
this.application.getControllerForElementAndIdentifier(element, identifier)
— возвращает экземпляр контроллера для указанного элемента и
идентификатора.Пример:
// child_controller.js
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
connect() {
const parent = this.application.getControllerForElementAndIdentifier(
this.element.closest("[data-controller='parent']"),
"parent"
);
parent.highlightItems();
}
}
Stimulus активно использует Custom Events для общения между контроллерами:
Пример:
// child_controller.js
this.element.dispatchEvent(new CustomEvent("child:clicked", {
bubbles: true,
detail: { value: this.element.textContent }
}));
// parent_controller.js
this.element.addEventListener("child:clicked", event => {
console.log(`Событие от дочернего: ${event.detail.value}`);
});
Использование bubbles: true позволяет событию
подниматься по DOM до родителя, что упрощает взаимодействие в
иерархии.
При динамическом добавлении элементов в DOM, Stimulus автоматически
инициализирует вложенные контроллеры, если у них
присутствует атрибут data-controller. Это делает иерархию
контроллеров гибкой и масштабируемой:
const newChild = document.createElement("div");
newChild.setAttribute("data-controller", "child");
parentElement.appendChild(newChild);
// Stimulus автоматически подключит child_controller к newChild
Эта схема позволяет создавать сложные, интерактивные интерфейсы с минимальными связями между компонентами и полной управляемостью через Stimulus API.