Создание плагинов

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


Структура плагина

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

const myPlugin = {
  /** Вызывается при инициализации компонента */
  connectedCallback(component) {
    console.log('Компонент подключен', component);
  },

  /** Вызывается при изменении состояния или свойств компонента */
  propertyChanged(component, propertyName, oldValue, newValue) {
    console.log(`Свойство ${propertyName} изменилось с ${oldValue} на ${newValue}`);
  },

  /** Вызывается перед удалением компонента из DOM */
  disconnectedCallback(component) {
    console.log('Компонент отключен', component);
  }
};
  • connectedCallback — добавляет поведение при подключении компонента в DOM.
  • propertyChanged — позволяет отслеживать изменения свойств и выполнять соответствующие действия.
  • disconnectedCallback — используется для очистки ресурсов, отмены подписок или таймеров.

Регистрация плагина

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

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

class MyElement extends FASTElement {}

const template = html<MyElement>`<div>${x => x.content}</div>`;
const styles = css`div { color: blue; }`;

MyElement.define({
  name: 'my-element',
  template,
  styles,
  behaviors: [myPlugin]
});

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


Плагины как функции

Помимо объектов, FAST Element поддерживает плагины, реализованные как функции, которые принимают компонент и возвращают объект с методами жизненного цикла:

function loggerPlugin() {
  return {
    connectedCallback(component) {
      console.log('Подключен компонент', component);
    },
    propertyChanged(component, prop, oldVal, newVal) {
      console.log(`${prop} изменилось с ${oldVal} на ${newVal}`);
    }
  };
}

MyElement.define({
  name: 'my-element',
  template,
  styles,
  behaviors: [loggerPlugin()]
});

Такой подход удобен, когда необходимо передавать конфигурацию плагину:

function configurableLogger(level) {
  return {
    connectedCallback(component) {
      if (level === 'debug') {
        console.log('DEBUG:', component);
      }
    }
  };
}

Манипуляции с состоянием компонента

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

const statePlugin = {
  connectedCallback(component) {
    if (!component.isInitialized) {
      component.isInitialized = true;
      component.content = 'Привет, FAST!';
    }
  },

  propertyChanged(component, propertyName, oldValue, newValue) {
    if (propertyName === 'content') {
      console.log('Новое содержимое:', newValue);
    }
  }
};

Изменения свойств через плагины автоматически вызывают обновление шаблона, если свойства задекларированы как реактивные через @observable.


Композиция плагинов

FAST Element поддерживает подключение нескольких плагинов одновременно. Порядок их применения может быть критичен:

const pluginA = {
  connectedCallback() { console.log('A'); }
};
const pluginB = {
  connectedCallback() { console.log('B'); }
};

MyElement.define({
  name: 'my-element',
  template,
  behaviors: [pluginA, pluginB]
});

В этом примере при подключении компонента сначала вызовется connectedCallback плагина pluginA, затем pluginB. Для сложных сценариев часто создают фабрики плагинов, которые объединяют несколько логик в один объект.


Отслеживание событий и реакция на DOM

Плагины могут добавлять слушатели событий напрямую на компонент или на его элементы DOM:

const eventPlugin = {
  connectedCallback(component) {
    component.addEventListener('click', component.handleClick);
  },

  disconnectedCallback(component) {
    component.removeEventListener('click', component.handleClick);
  }
};

class ClickElement extends FASTElement {
  handleClick() {
    console.log('Компонент кликнут');
  }
}

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


Использование плагинов для расширения шаблона

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

const themePlugin = {
  connectedCallback(component) {
    component.theme = 'dark';
  },

  propertyChanged(component, propertyName, oldValue, newValue) {
    if (propertyName === 'theme') {
      component.style.backgroundColor = newValue === 'dark' ? '#333' : '#fff';
    }
  }
};

Такой подход позволяет централизованно управлять стилями и состояниями без необходимости модифицировать HTML-шаблон компонента.


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

  • Использовать чистые функции и объекты, избегать глобальных переменных.
  • Освобождать ресурсы в disconnectedCallback.
  • Минимизировать прямые манипуляции с DOM, отдавая предпочтение реактивным свойствам.
  • Поддерживать конфигурируемость через фабрики плагинов.
  • Объединять несколько плагинов в один для упрощения композиции и контроля порядка вызовов.

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