Условное применение классов

Stimulus — это легковесный JavaScript-фреймворк, ориентированный на добавление поведения к существующей разметке через контроллеры и привязку действий к событиям. Одной из ключевых возможностей является динамическое управление состоянием элементов, включая условное применение CSS-классов. Этот механизм позволяет изменять внешний вид элементов без прямого вмешательства в DOM через методы вроде classList.add или classList.remove, делая код более декларативным и поддерживаемым.


Контроллеры и целевые элементы

В Stimulus управление классами происходит через контроллеры, которые связываются с DOM через атрибут data-controller. Для управления конкретными элементами внутри контроллера используются target-ы:

<div data-controller="toggle">
  <button data-action="click->toggle#switch" data-toggle-target="button">Нажми меня</button>
  <div data-toggle-target="panel" class="panel">Контент панели</div>
</div>
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["panel", "button"]

  switch() {
    this.panelTarget.classList.toggle("active")
  }
}

В примере класс active добавляется или удаляется у панели при нажатии кнопки. Это базовый способ работы с классами, который легко масштабируется при условной логике.


Условные классы через свойства контроллера

Stimulus позволяет хранить состояние контроллера в свойствах, что облегчает условное применение классов. Например, можно поддерживать состояние active:

export default class extends Controller {
  static targets = ["panel"]
  isActive = false

  toggle() {
    this.isActive = !this.isActive
    this.updateClass()
  }

  updateClass() {
    this.panelTarget.classList.toggle("active", this.isActive)
  }
}

Метод classList.toggle с двумя аргументами позволяет явно задавать, добавлять ли класс, основываясь на булевом значении. Это устраняет необходимость писать условные конструкции вроде if/else для управления классами.


Множественные условные классы

Для элементов с несколькими состояниями удобно применять несколько классов одновременно:

updateClass() {
  this.panelTarget.classList.toggle("active", this.isActive)
  this.panelTarget.classList.toggle("highlighted", this.isHighlighted)
  this.panelTarget.classList.toggle("disabled", !this.isEnabled)
}

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


Связывание классов с событиями

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

<button data-action="mouseenter->tooltip#show mouseleave->tooltip#hide">Hover me</button>
<div data-tooltip-target="popup" class="tooltip">Подсказка</div>
export default class extends Controller {
  static targets = ["popup"]

  show() {
    this.popupTarget.classList.add("visible")
  }

  hide() {
    this.popupTarget.classList.remove("visible")
  }
}

Использование методов add и remove обеспечивает чёткое управление классами, в отличие от чистой замены className, которая может случайно удалить другие стили.


Динамические классы через значения

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

<div data-controller="status"
     data-status-active-value="true"
     data-status-target="indicator">
  <div data-status-target="indicator" class="indicator"></div>
</div>
export default class extends Controller {
  static targets = ["indicator"]
  static values = { active: Boolean }

  connect() {
    this.updateClass()
  }

  activeValueChanged() {
    this.updateClass()
  }

  updateClass() {
    this.indicatorTarget.classList.toggle("active", this.activeValue)
  }
}

При изменении activeValue автоматически вызывается метод activeValueChanged, который обновляет классы элемента. Такой подход особенно полезен для состояний, зависящих от внешних данных, например, флагов активности или состояния загрузки.


Комбинирование с CSS-переменными

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

updateStyle() {
  this.panelTarget.style.setProperty('--opacity', this.isActive ? '1' : '0.5')
}

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


Рекомендации по организации классов

  • Использовать classList.toggle с булевыми аргументами для упрощения логики.
  • Разделять состояния на отдельные свойства контроллера.
  • Для сложных элементов применять несколько target-ов и отдельные методы для обновления классов.
  • Использовать Value API для привязки динамических данных к визуальному состоянию.
  • Избегать прямой замены className, чтобы не нарушать существующие стили.

Эти методы позволяют поддерживать чистый, читаемый и легко расширяемый код при условном применении классов в Stimulus.