Отражение атрибутов

FAST Element предоставляет мощный механизм для синхронизации атрибутов HTML с внутренними свойствами компонентов, что позволяет создавать реактивные, настраиваемые и легко управляемые веб-компоненты. Основная концепция здесь — reflection, или отражение атрибутов.


Свойства и атрибуты

В FAST Element каждое свойство класса компонента может быть связано с атрибутом HTML. Для этого используется декоратор @attr из библиотеки @microsoft/fast-element. Свойство с атрибутом автоматически:

  • Синхронизируется с соответствующим атрибутом.
  • Обеспечивает конвертацию типов.
  • Вызывает обновление шаблона при изменении.

Пример:

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

class MyButton extends FASTElement {
    @attr text;        // отражение строки
    @attr({ mode: "boolean" }) disabled; // отражение булевого значения
}

const template = html<MyButton>`
    <button ?disabled="${x => x.disabled}">${x => x.text}</button>
`;

MyButton.define({ name: "my-button", template });

В этом примере:

  • Атрибут text отражается на свойство text.
  • Булевый атрибут disabled синхронизируется с соответствующим свойством и автоматически конвертируется в true/false.

Режимы отражения

FAST Element поддерживает несколько режимов отражения, задаваемых через опцию mode:

  1. string (по умолчанию) — обычное текстовое отражение.
  2. boolean — атрибут присутствует только при значении true.
  3. number — автоматическая конвертация числа в строку и обратно.
  4. fromView / toView — пользовательские функции конвертации.

Пример кастомной конверсии:

@attr({
    mode: "fromView",
    converter: {
        fromView(value) {
            return parseInt(value, 10);
        },
        toView(value) {
            return value.toString();
        }
    }
})
count;

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


Обновление шаблона

Отражение атрибутов тесно связано с реактивностью. Любое изменение свойства, связанного с атрибутом, инициирует автоматическое обновление DOM. FAST Element использует механизм наблюдаемых свойств (observable properties), что позволяет избежать ручной работы с MutationObserver или кастомными событиями.

Пример реактивного поведения:

class Counter extends FASTElement {
    @attr({ mode: "number" }) value = 0;

    increment() {
        this.value += 1; // автоматически обновляется атрибут и шаблон
    }
}

const template = html<Counter>`
    <div>Счёт: ${x => x.value}</div>
    <button @click="${x => x.increment()}">+</button>
`;

Counter.define({ name: "counter-element", template });

При изменении value атрибут value на элементе синхронизируется автоматически, а содержимое <div> обновляется без дополнительных усилий.


Свойства без отражения

Не все свойства компонента должны отражаться на атрибуты. FAST Element позволяет создавать невидимые для HTML свойства, которые остаются внутренними. Для этого не используется @attr, а просто объявляется обычное свойство:

class UserCard extends FASTElement {
    name;       // внутреннее свойство
    @attr age;  // отражаемое свойство
}

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


Настройка поведения отражения

Опции декоратора @attr позволяют детально управлять отражением:

  • attribute: string — указание имени атрибута, отличного от имени свойства.
  • mode — тип отражения (string, boolean, number или кастомный).
  • converter — объект с функциями fromView и toView.
  • reflect — булевое значение, указывающее, нужно ли синхронизировать свойство с атрибутом при изменении свойства (по умолчанию true).

Пример:

@attr({ attribute: "user-age", mode: "number" })
age;

Теперь свойство age синхронизируется с атрибутом user-age вместо age.


Взаимодействие с булевыми атрибутами

Булевые атрибуты имеют особенность: их наличие обозначает true, а отсутствие — false. FAST Element автоматически учитывает это при отражении:

class ToggleSwitch extends FASTElement {
    @attr({ mode: "boolean" }) checked;
}

const template = html<ToggleSwitch>`
    <input type="checkbox" ?checked="${x => x.checked}">
`;

При установке checked = true в элемент добавляется атрибут checked, при false — удаляется.


Динамическое связывание атрибутов

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


Важные рекомендации

  • Для чисел и булевых значений всегда использовать режим number или boolean для корректной синхронизации с DOM.
  • Не использовать отражение для приватных или вычисляемых свойств, чтобы избежать лишнего DOM-шумa.
  • При необходимости кастомной конверсии использовать converter, чтобы корректно обрабатывать данные между свойствами и атрибутами.

Отражение атрибутов в FAST Element обеспечивает мощный, гибкий и безопасный способ управления состоянием компонентов через HTML, объединяя реактивность и контроль над DOM без лишнего кода. Это фундаментальная часть построения современных веб-компонентов с полной интеграцией в стандартные HTML-атрибуты.