Создание контроллеров

FAST Element — это библиотека для создания веб-компонентов, обеспечивающая высокую производительность и гибкость. Контроллеры в FAST Element позволяют инкапсулировать логику, отделяя поведение компонента от его структуры и состояния, что повышает повторное использование кода и упрощает тестирование.

Понятие контроллера

Контроллер в FAST Element — это объект, реализующий интерфейс Controller, который может управлять жизненным циклом компонента. Контроллеры не заменяют сам компонент, а расширяют его функциональность, реагируя на события и изменения состояния.

Основной контракт контроллера включает методы:

  • connectedCallback() — вызывается, когда компонент присоединён к DOM. Подходит для регистрации слушателей событий или инициализации данных.
  • disconnectedCallback() — вызывается при удалении компонента из DOM. Используется для очистки ресурсов и отписки от событий.
  • update() — вызывается при обновлении компонента, например, при изменении наблюдаемых свойств. Позволяет синхронизировать состояние контроллера с состоянием компонента.
  • render() — необязательный метод, если контроллер управляет отображением напрямую.

Создание собственного контроллера

Контроллер определяется как класс, реализующий методы интерфейса Controller. Пример базового контроллера:

import { Controller } from "@microsoft/fast-element";

class LoggerController {
    constructor(host) {
        this.host = host;
    }

    connectedCallback() {
        console.log(`${this.host.constructor.name} подключён к DOM`);
    }

    disconnectedCallback() {
        console.log(`${this.host.constructor.name} удалён из DOM`);
    }

    update() {
        console.log(`${this.host.constructor.name} обновлён`);
    }
}

Для подключения контроллера к компоненту используется декоратор @controller или статическое свойство controllers:

import { FASTElement, html, css } from "@microsoft/fast-element";

class MyComponent extends FASTElement {
    static controllers = [LoggerController];
    
    connectedCallback() {
        super.connectedCallback();
    }
}

Передача параметров в контроллер

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

class TimerController {
    constructor(host, interval = 1000) {
        this.host = host;
        this.interval = interval;
        this.timer = null;
    }

    connectedCallback() {
        this.timer = setInterval(() => {
            this.host.time = new Date().toLocaleTimeString();
        }, this.interval);
    }

    disconnectedCallback() {
        clearInterval(this.timer);
    }
}

class ClockComponent extends FASTElement {
    time = "";
    static controllers = [new TimerController(this, 1000)];
}

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

Реакция на изменения свойств

Контроллер может отслеживать изменения наблюдаемых свойств компонента с помощью методов hostChanged или подписки на события:

class PropertyObserverController {
    constructor(host) {
        this.host = host;
    }

    connectedCallback() {
        this.host.$fastController.addBehavior({
            propertyChanged: (property, oldValue, newValue) => {
                if (property === "status") {
                    console.log(`Свойство status изменено с ${oldValue} на ${newValue}`);
                }
            }
        });
    }
}

class StatusComponent extends FASTElement {
    status = "idle";
    static controllers = [PropertyObserverController];
}

Управление событиями в контроллере

Контроллеры позволяют централизованно управлять событиями компонента. Это удобно для повторно используемых модулей:

class ClickCounterController {
    constructor(host) {
        this.host = host;
        this.count = 0;
        this.onCl ick = this.onClick.bind(this);
    }

    connectedCallback() {
        this.host.addEventListener("click", this.onClick);
    }

    disconnectedCallback() {
        this.host.removeEventListener("click", this.onClick);
    }

    onClick() {
        this.count++;
        console.log(`Элемент кликнут ${this.count} раз`);
    }
}

class ButtonComponent extends FASTElement {
    static controllers = [ClickCounterController];
}

Встроенные контроллеры FAST Element

FAST предоставляет готовые контроллеры для типичных задач:

  • ObservableController — для реакции на изменения свойств компонента.
  • DelegatesFocusController — управление фокусом в теневом DOM.
  • FormAssociatedController — интеграция с формами HTML.

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

Комбинирование нескольких контроллеров

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

class TooltipController {
    connectedCallback() {
        console.log("Tooltip активирован");
    }
}

class AnimationController {
    connectedCallback() {
        console.log("Анимация включена");
    }
}

class AnimatedButton extends FASTElement {
    static controllers = [TooltipController, AnimationController];
}

Контроллеры подключаются в порядке перечисления и управляются FAST Element автоматически, вызывая их методы жизненного цикла при соответствующих событиях DOM.

Практические рекомендации

  • Контроллеры должны быть максимально автономными и не изменять внутренние детали компонента напрямую.
  • Использовать контроллеры для повторно используемых функций: таймеры, обработка событий, интеграция с внешними библиотеками.
  • Следить за очисткой ресурсов в disconnectedCallback, чтобы избежать утечек памяти.
  • Разделять логику представления и поведения, используя контроллеры для управления состоянием и событийной логики, оставляя шаблон чистым.

Контроллеры в FAST Element обеспечивают мощный инструмент для модульного построения компонентов, делая код более читаемым, тестируемым и поддерживаемым.