Shadow DOM в FAST Element

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

В FAST Element каждый компонент, наследующийся от FASTElement, по умолчанию может использовать Shadow DOM. Создание компонента с Shadow DOM осуществляется через метод @customElement и свойство shadowOptions:

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

const template = html<MyComponent>`
    <div class="container">
        <span>${x => x.text}</span>
    </div>
`;

const styles = css`
    .container {
        background-color: #f0f0f0;
        padding: 10px;
    }
    span {
        color: #333;
    }
`;

@customElement({
    name: "my-component",
    template,
    styles,
    shadowOptions: { mode: "open" } // Shadow DOM включен
})
class MyComponent extends FASTElement {
    text = "Привет, FAST!";
}

Ключевой момент: shadowOptions.mode принимает значения open или closed.

  • open позволяет получить доступ к shadowRoot извне через element.shadowRoot.
  • closed скрывает shadowRoot, что повышает инкапсуляцию.

Инкапсуляция стилей

Shadow DOM в FAST Element обеспечивает локальные стили, которые применяются только к внутренней структуре компонента. Это предотвращает утечку стилей наружу и конфликт с глобальными CSS. Например, можно создавать сложные компоненты с вложенными элементами, не опасаясь, что внешние классы изменят их внешний вид.

const template = html<MyCard>`
    <div class="card">
        <header>${x => x.title}</header>
        <section>${x => x.content}</section>
    </div>
`;

const styles = css`
    .card {
        border: 1px solid #ccc;
        border-radius: 8px;
        padding: 16px;
        background-color: #fff;
    }
    header {
        font-weight: bold;
        margin-bottom: 8px;
    }
`;

Даже если глобальный CSS определяет стиль header { color: red; }, внутри компонента MyCard стиль Shadow DOM будет сохранять локальный цвет.

Слоты и композиция

Shadow DOM в FAST Element поддерживает слоты, что позволяет создавать гибкие шаблоны с местом для контента, передаваемого из внешнего DOM. Слоты обеспечивают контроль над тем, какие элементы будут вставлены внутрь компонента.

const template = html<MyPanel>`
    <div class="panel">
        <header><slot name="header"></slot></header>
        <main><slot></slot></main>
    </div>
`;

Использование слотов позволяет разделять структуру компонента и контент, сохраняя при этом полную инкапсуляцию стилей.

<my-panel>
    <span slot="header">Заголовок панели</span>
    <p>Основной контент панели</p>
</my-panel>

Scoped CSS и кастомные свойства

FAST Element позволяет использовать CSS-переменные для изменения стилей компонентов без нарушения инкапсуляции. Переменные определяются глобально, но применяются локально через Shadow DOM:

:host {
    --panel-bg: #fafafa;
    --panel-color: #222;
}

.panel {
    background-color: var(--panel-bg);
    color: var(--panel-color);
    padding: 12px;
    border-radius: 6px;
}

:host используется для стилизации корневого элемента shadowRoot. Он позволяет управлять внешним видом компонента, не затрагивая внутренние классы.

Работа с событиями

Shadow DOM в FAST Element полностью поддерживает кастомные события. Внутри компонента события могут всплывать и быть перехвачены извне, но при этом событие можно сделать приватным через composed: false:

this.dispatchEvent(new CustomEvent("panelOpen", {
    bubbles: true,
    composed: true, // событие пробивается через shadow DOM
    detail: { open: true }
}));

Использование composed: true позволяет событию проходить через границы Shadow DOM, что необходимо для интеграции компонентов в сложные приложения.

Динамическая замена шаблонов

FAST Element поддерживает динамическое управление Shadow DOM через директивы и условный рендеринг. Это особенно полезно для компонентов с изменяющейся структурой:

const template = html<MyToggle>`
    <button @click=${x => x.toggle()}>Переключить</button>
    ${x => x.isOpen ? html`<div>Содержимое открыто</div>` : html``}
`;

В таком подходе структура DOM внутри shadowRoot обновляется без изменения внешнего DOM, сохраняя преимущества инкапсуляции.

Особенности производительности

Shadow DOM минимизирует риски конфликтов стилей, но может увеличивать количество нод в DOM. FAST Element оптимизирует работу через обновление только изменённых частей шаблона, что снижает накладные расходы. Использование html и директив позволяет максимально эффективно управлять рендерингом внутри Shadow DOM.

Итоговые рекомендации по Shadow DOM в FAST Element

  • Всегда использовать shadowOptions.mode: "open" для компонентов, где нужен доступ к shadowRoot.
  • Применять :host для управления стилями корневого элемента.
  • Использовать слоты для гибкой композиции и передачи контента извне.
  • Для событий учитывать composed, чтобы контролировать их пробивание через Shadow DOM.
  • Динамическая рендеринг с FAST Element минимизирует обновления DOM и повышает производительность.

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