Стратегия для вариативного поведения

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


Контроллеры и их динамическое управление

В основе Stimulus лежат контроллеры, которые привязываются к DOM через атрибут data-controller. Контроллеры содержат методы, вызываемые при событиях (data-action) и свойства (targets) для обращения к определённым элементам.

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

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

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

  connect() {
    this.mode = "view"; // начальный режим
    this.updateUI();
  }

  switchMode(event) {
    this.mode = event.params.mode;
    this.updateUI();
  }

  updateUI() {
    if (this.mode === "edit") {
      this.outputTarget.contentEditable = true;
      this.outputTarget.classList.add("editing");
    } else {
      this.outputTarget.contentEditable = false;
      this.outputTarget.classList.remove("editing");
    }
  }
}

Ключевой момент: контроллер сам определяет, какое поведение должно выполняться, основываясь на внутреннем состоянии mode.


Использование параметров и динамических атрибутов

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

<div data-controller="toggle" data-toggle-mode-param="dark"></div>

В контроллере доступ к параметрам реализуется через this.params.get("mode"). Это позволяет создавать универсальные контроллеры, которые ведут себя по-разному в зависимости от контекста DOM.

connect() {
  this.mode = this.params.get("mode") || "light";
  this.applyMode();
}

applyMode() {
  document.body.className = `theme-${this.mode}`;
}

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


Работа с множественными таргетами

Для вариативного поведения критично использование множественных targets. Они позволяют разделять логику на независимые элементы внутри одного контроллера.

static targets = ["item", "button"];

highlightItem(event) {
  this.itemTargets.forEach(el => el.classList.remove("highlight"));
  event.currentTarget.classList.add("highlight");
}

Такой подход упрощает манипуляции с группой элементов и позволяет создавать сложные интерактивные интерфейсы без дублирования кода.


Динамическая регистрация событий

Stimulus поддерживает data-action для связывания событий с методами контроллера, но для вариативного поведения полезна динамическая регистрация обработчиков событий:

connect() {
  this.handleClick = this.handleClick.bind(this);
  this.element.addEventListener("click", this.handleClick);
}

disconnect() {
  this.element.removeEventListener("click", this.handleClick);
}

handleClick(event) {
  if (this.mode === "edit") {
    console.log("Редактирование");
  } else {
    console.log("Просмотр");
  }
}

Такой подход позволяет изменять поведение элемента во время работы приложения, не создавая новые контроллеры.


Комбинация с другими контроллерами

Вариативное поведение часто реализуется через комбинирование контроллеров, где один контроллер отвечает за состояние, а другой — за визуальное представление:

<div data-controller="mode state">
  <div data-state-target="display"></div>
  <button data-action="mode#toggle">Переключить</button>
</div>
// StateController
export default class extends Controller {
  static targets = ["display"];
  connect() {
    this.state = "view";
  }
  setState(newState) {
    this.state = newState;
    this.displayTarget.textContent = `Текущий режим: ${this.state}`;
  }
}

// ModeController
export default class extends Controller {
  toggle() {
    const stateController = this.application.getControllerForElementAndIdentifier(this.element, "state");
    stateController.setState(stateController.state === "view" ? "edit" : "view");
  }
}

Комбинирование позволяет разделить логику и интерфейс, сохраняя контроллеры чистыми и легко поддерживаемыми.


Применение стратегий

  • Паттерн состояния (State Pattern) — внутреннее хранение состояния контроллера (mode, status) и переключение поведения через методы.
  • Параметры как стратегия конфигурации — использование data-* атрибутов для вариативной настройки одного контроллера.
  • Композиция контроллеров — разделение логики состояния и визуальной реакции на разные контроллеры.
  • Динамическая регистрация обработчиков — возможность изменять реакцию на события без перезагрузки DOM.

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


Stimulus предоставляет минималистичный, но мощный инструментарий для реализации вариативного поведения, позволяя контроллерам быть одновременно лёгкими, гибкими и контекстно адаптивными.