Работа с Shadow DOM

Shadow DOM — это технология, позволяющая создавать изолированные области DOM внутри компонентов. Она обеспечивает инкапсуляцию стилей и структуры элементов, предотвращая конфликт с остальной частью страницы. Slim.js поддерживает работу с Shadow DOM через встроенные возможности компонентов и предоставляет удобный API для управления его содержимым.


Создание компонента с Shadow DOM

В Slim.js Shadow DOM создается при определении компонента с использованием свойства shadow: true или метода attachShadow(). Простейший пример:

class MyComponent extends Slim {
    get useShadow() { return true; }

    template() {
        return `
            <style>
                p { color: blue; font-weight: bold; }
            </style>
            <p>Текст внутри Shadow DOM</p>
        `;
    }
}

customElements.define('my-component', MyComponent);

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

  • get useShadow() { return true; } — включение Shadow DOM.
  • Стили внутри шаблона применяются только к элементам компонента.
  • Разметка компонента полностью изолирована от внешнего DOM.

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

Shadow DOM обеспечивает локальные стили, которые не влияют на глобальные CSS и не наследуются внешними элементами. В Slim.js это достигается следующим образом:

template() {
    return `
        <style>
            div { background-color: #f0f0f0; padding: 10px; }
            span { color: red; }
        </style>
        <div>
            <span>Изолированный текст</span>
        </div>
    `;
}

Любой <div> или <span> вне компонента останется нетронутым. Это позволяет создавать многократно используемые компоненты без риска сломать стили страницы.


Доступ к Shadow DOM из JavaScript

Slim.js предоставляет методы для работы с Shadow DOM через обычные DOM-API:

connectedCallback() {
    super.connectedCallback();
    const shadowRoot = this.shadowRoot;
    const paragraph = shadowRoot.querySelector('p');
    paragraph.textContent = 'Обновленный текст';
}

Особенности доступа:

  • this.shadowRoot возвращает корневой элемент Shadow DOM компонента.
  • Методы querySelector и querySelectorAll работают только внутри Shadow DOM.
  • Внешний DOM не имеет прямого доступа к внутренним элементам компонента.

Слоты и распределение контента

Shadow DOM позволяет создавать слоты, которые вставляют контент из родительского DOM внутрь компонента:

template() {
    return `
        <style> ::slotted(*) { color: green; } </style>
        <slot></slot>
    `;
}

Использование:

<my-component>
    <p>Этот текст попадет в слот</p>
</my-component>

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

  • Контент из родителя проходит внутрь Shadow DOM через <slot>.
  • Стили внутри Shadow DOM можно применять к слоту через ::slotted().
  • Несколько слотов позволяют создавать сложные шаблоны с распределением контента по различным областям.

Варианты режима Shadow DOM

При создании Shadow DOM можно выбрать режим инкапсуляции:

  • openthis.shadowRoot доступен извне.
  • closed — доступ к shadowRoot невозможен через внешний код.

В Slim.js это задается через метод:

constructor() {
    super();
    this.attachShadow({ mode: 'open' });
}

Рекомендации:

  • Для компонентов с публичным API используется open.
  • Для полностью внутренней логики, где доступ извне не нужен, подходит closed.

Динамическое обновление Shadow DOM

Slim.js поддерживает реактивные обновления шаблона даже внутри Shadow DOM:

class CounterComponent extends Slim {
    count = 0;

    get useShadow() { return true; }

    template() {
        return `
            <div>Счетчик: ${this.count}</div>
            <button oncl ick="${() => this.increment()}">+</button>
        `;
    }

    increment() {
        this.count++;
        this.update();
    }
}

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

  • Метод this.update() перерисовывает Shadow DOM с текущими данными.
  • Изменения не затрагивают глобальный DOM.
  • Реактивность работает с любыми свойствами компонента.

Советы по использованию Shadow DOM в Slim.js

  • Использовать Shadow DOM для создания самодостаточных компонентов, которые не зависят от внешних стилей.
  • Для сложных UI с динамическим контентом комбинировать слоты и реактивные свойства.
  • Избегать глобальных селекторов внутри Shadow DOM (body, html), так как они не имеют эффекта.
  • При необходимости интеграции с внешними библиотеками, которые используют глобальный DOM, учитывать ограничения инкапсуляции Shadow DOM.

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