Декоратор для расширения функциональности

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

Основы декораторов в Stimulus

Декоратор — это функция, которая применяется к методу или свойству класса и изменяет его поведение. В контексте Stimulus декораторы часто используются для:

  • Автоматического связывания методов с элементами DOM.
  • Расширения стандартной логики действий (actions).
  • Добавления вспомогательных проверок или логирования.

Простейший пример декоратора выглядит так:

function logMethod(target, key, descriptor) {
  const original = descriptor.value;
  descriptor.value = function (...args) {
    console.log(`Вызван метод ${key} с аргументами:`, args);
    return original.apply(this, args);
  };
  return descriptor;
}

Декоратор logMethod оборачивает метод контроллера и добавляет логирование каждого вызова. Для применения его в Stimulus:

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

export default class extends Controller {
  @logMethod
  connect() {
    console.log("Контроллер подключен");
  }
}

Декораторы для управления действиями (Actions)

Stimulus активно использует HTML-атрибуты для привязки действий. Декораторы могут облегчить обработку этих действий, добавляя проверку или дополнительные эффекты. Например, декоратор для предотвращения стандартного поведения событий:

function preventDefault(target, key, descriptor) {
  const original = descriptor.value;
  descriptor.value = function (event, ...args) {
    event.preventDefault();
    return original.apply(this, [event, ...args]);
  };
  return descriptor;
}

export default class extends Controller {
  @preventDefault
  handleClick(event) {
    console.log("Клик обработан без стандартного поведения");
  }
}

В HTML:

<button data-action="click->my-controller#handleClick">Нажать</button>

Использование декоратора preventDefault гарантирует, что стандартное поведение кнопки (например, отправка формы) не выполнится, сохраняя при этом чистую логику контроллера.

Связывание методов с жизненным циклом контроллера

Stimulus предоставляет методы жизненного цикла (connect, disconnect, initialize). Декораторы позволяют добавлять к этим методам дополнительную функциональность, не изменяя основной код:

function measureExecutionTime(target, key, descriptor) {
  const original = descriptor.value;
  descriptor.value = function (...args) {
    const start = performance.now();
    const result = original.apply(this, args);
    const end = performance.now();
    console.log(`${key} выполнен за ${end - start} мс`);
    return result;
  };
  return descriptor;
}

export default class extends Controller {
  @measureExecutionTime
  connect() {
    console.log("Подключение контроллера завершено");
  }
}

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

Создание параметризованных декораторов

Декораторы могут принимать аргументы для гибкой настройки. Например, декоратор для условного логирования:

function conditionalLog(enabled = true) {
  return function (target, key, descriptor) {
    const original = descriptor.value;
    descriptor.value = function (...args) {
      if (enabled) {
        console.log(`Метод ${key} вызван с аргументами:`, args);
      }
      return original.apply(this, args);
    };
    return descriptor;
  };
}

export default class extends Controller {
  @conditionalLog(false)
  handleEvent(event) {
    console.log("Событие обработано");
  }
}

Параметризованные декораторы позволяют включать или отключать дополнительную функциональность без изменения основного метода контроллера.

Расширение функциональности через миксины и декораторы

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

function withTooltip(target, key, descriptor) {
  const original = descriptor.value;
  descriptor.value = function (...args) {
    original.apply(this, args);
    this.element.setAttribute("title", "Подсказка");
  };
  return descriptor;
}

const TooltipMixin = (Base) =>
  class extends Base {
    @withTooltip
    connect() {
      console.log("Контроллер с подсказкой подключен");
    }
  };

export default class extends TooltipMixin(Controller) {}

Использование миксинов с декораторами позволяет добавлять новые возможности контроллерам без дублирования кода.

Рекомендации по применению

  • Декораторы следует использовать для повторяющейся логики, чтобы уменьшить дублирование.
  • Следует избегать чрезмерного усложнения методов контроллера декораторами — лучше разделять обязанности.
  • Декораторы удобны для логирования, проверки условий, предотвращения стандартного поведения и расширения методов жизненного цикла.
  • Для крупных проектов рекомендуется создавать библиотеку собственных декораторов, обеспечивая единый стиль и стандарты взаимодействия контроллеров.

Декораторы в Stimulus превращают простые контроллеры в гибкие и расширяемые модули, упрощая поддержку и масштабирование интерактивных элементов веб-приложений.