Создание пользовательских поведений

FAST Element — это современная библиотека для создания веб-компонентов на JavaScript, предоставляющая гибкий механизм для расширения функциональности через поведения (behaviors). Поведения позволяют инкапсулировать повторно используемую логику и применять её к нескольким элементам без дублирования кода.

Понятие поведения

Поведение в FAST Element — это объект, который может содержать методы жизненного цикла, реактивные свойства, обработчики событий и декларативные привязки. Основная задача поведения — расширить функциональность элемента без необходимости изменять его исходный код. Оно создаётся как класс или объект с определёнными свойствами и методами.

Пример базовой структуры поведения:

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

export class HighlightBehavior extends Behavior {
    constructor(options) {
        super();
        this.options = options;
    }

    attached(element) {
        element.addEventListener('mouseenter', this.onMouseEnter);
        element.addEventListener('mouseleave', this.onMouseLeave);
    }

    detached(element) {
        element.removeEventListener('mouseenter', this.onMouseEnter);
        element.removeEventListener('mouseleave', this.onMouseLeave);
    }

    onMouseEnter(event) {
        event.target.style.backgroundColor = this.options.color || 'yellow';
    }

    onMouseLeave(event) {
        event.target.style.backgroundColor = '';
    }
}

Ключевые моменты:

  • attached и detached — методы жизненного цикла поведения, вызываемые при подключении и удалении элемента из DOM.
  • Можно передавать опции, чтобы поведение было гибким.
  • Обработчики событий инкапсулированы внутри поведения.

Применение поведения к элементу

Для использования поведения необходимо подключить его к элементу через withBehaviors:

import { FASTElement, html, css, withBehaviors } from "@microsoft/fast-element";
import { HighlightBehavior } from "./highlight-behavior.js";

const template = html<MyButton>`
  <button>
    <slot></slot>
  </button>
`;

const styles = css`
  button {
    font-size: 16px;
    padding: 8px 12px;
  }
`;

class MyButton extends FASTElement {}

MyButton.compose({
    baseName: 'my-button',
    template,
    styles,
    behaviors: [new HighlightBehavior({ color: 'lightblue' })]
});

Основные особенности:

  • compose используется для регистрации элемента с поведениями.
  • Поведение добавляется в массив behaviors.
  • Поведения могут быть множественными, применяться одновременно и взаимодействовать между собой.

Создание реактивных свойств в поведениях

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

import { Behavior, observable } from "@microsoft/fast-element";

export class ToggleBehavior extends Behavior {
    @observable isActive = false;

    attached(element) {
        element.addEventListener('click', () => this.toggle());
    }

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

При изменении свойства isActive можно динамически менять внешний вид элемента через привязку в шаблоне:

const template = html<MyToggleButton>`
  <button class="${x => x.isActive ? 'active' : ''}">
    <slot></slot>
  </button>
`;

const styles = css`
  .active {
    background-color: green;
    color: white;
  }
`;

Обработка событий внутри поведений

Поведения позволяют инкапсулировать логику событий, включая пользовательские события:

class NotifyBehavior extends Behavior {
    attached(element) {
        element.addEventListener('click', this.handleClick);
    }

    detached(element) {
        element.removeEventListener('click', this.handleClick);
    }

    handleClick = (event) => {
        event.target.dispatchEvent(new CustomEvent('element-clicked', {
            bubbles: true,
            composed: true,
            detail: { timestamp: Date.now() }
        }));
    }
}

Преимущества такого подхода:

  • Поведение остаётся независимым от структуры элемента.
  • Логика событий переиспользуема.
  • Можно легко комбинировать несколько поведений на одном элементе.

Композиция и повторное использование поведений

Одно из ключевых достоинств FAST Element — возможность создавать модули поведения и комбинировать их:

const buttonBehaviors = [
    new HighlightBehavior({ color: 'pink' }),
    new ToggleBehavior(),
    new NotifyBehavior()
];

MyButton.compose({
    baseName: 'composite-button',
    template,
    styles,
    behaviors: buttonBehaviors
});

Такой подход позволяет:

  • Минимизировать дублирование кода.
  • Создавать универсальные паттерны поведения для всего приложения.
  • Легко тестировать и модифицировать отдельные поведения без затрагивания элементов.

Советы по организации поведений

  1. Каждый класс поведения должен быть самодостаточным.
  2. Логика поведения должна не зависеть напрямую от конкретного элемента, а использовать методы жизненного цикла attached/detached.
  3. Использование реактивных свойств повышает гибкость и интеграцию с шаблонами.
  4. Поведения следует разбивать на мелкие, атомарные части, чтобы их можно было комбинировать.
  5. Для сложных элементов можно создавать поведения на основе других поведений, наследуя или комбинируя их методы.

Поведения в FAST Element создают мощный инструмент для построения реактивных, модульных и повторно используемых компонентов, обеспечивая чистую архитектуру и лёгкое масштабирование интерфейсов.