Shadow DOM использование

Shadow DOM — это технология веб-компонентов, позволяющая создавать инкапсулированные DOM-деревья с собственными стилями и скриптами. В контексте Vue.js Shadow DOM может применяться для повышения изоляции компонентов, предотвращения конфликтов CSS и управления внутренними состояниями компонентов без влияния глобального окружения.


Принципы работы Shadow DOM

  1. Инкапсуляция Shadow DOM создаёт отдельное DOM-дерево, привязанное к элементу-хосту. Внутренние элементы Shadow DOM изолированы от внешнего DOM, что означает:

    • стили из внешнего CSS не применяются внутри Shadow DOM, если не использовать ::part или ::slotted;
    • события всплывают до хоста, но дальше наружу не распространяются по стандартному DOM (кроме composed: true).
  2. Элементы-хосты Любой HTML-элемент может стать хостом Shadow DOM, используя метод attachShadow({ mode: 'open' }) или attachShadow({ mode: 'closed' }). В Vue.js это применяется через кастомные компоненты с опцией shadow: true.

  3. Стили и скопированные CSS CSS внутри Shadow DOM не конфликтует с глобальными стилями. Для передачи стилей из внешнего окружения используются:

    • CSS Custom Properties (переменные --variable)
    • слоты <slot> для вставки внешнего контента.

Shadow DOM в компонентах Vue.js

Vue.js начиная с версии 3 поддерживает создание компонентов с Shadow DOM через опцию customElement или shadow: true.

Пример базового компонента с Shadow DOM:

import { defineComponent, h } from 'vue';

export default defineComponent({
  name: 'ShadowButton',
  shadow: true,
  render() {
    return h('button', { class: 'shadow-btn' }, 'Кнопка');
  }
});
  • shadow: true создаёт инкапсулированный DOM для компонента.
  • Стили компонента можно добавлять локально в <style scoped> или через <style> внутри <template>.

Использование слотов внутри Shadow DOM

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

<template>
  <div>
    <slot name="header"></slot>
    <p>Основной контент компонента</p>
    <slot></slot>
  </div>
</template>

<script>
export default {
  shadow: true
}
</script>

<style scoped>
p {
  color: blue;
}
</style>
  • Контент, переданный через <slot> или <slot name="header">, рендерится внутри Shadow DOM, сохраняя инкапсуляцию стилей.
  • Внешние CSS свойства можно передавать через --custom-property для стилизации слотов.

Взаимодействие с внешним DOM

  1. События

    • События внутри Shadow DOM по умолчанию не всплывают наружу.
    • Для передачи событий используется опция composed: true при создании события:
this.$el.dispatchEvent(new CustomEvent('clicked', { bubbles: true, composed: true }));
  1. Доступ к элементам

    • Внутри Vue-компонента можно использовать this.$refs для доступа к элементам Shadow DOM.
    • Для доступа снаружи необходимо использовать метод shadowRoot.querySelector.

Применение CSS в Shadow DOM

Важное отличие: глобальные стили не применяются. Для управления стилями:

  1. Локальные стили компонента Использование <style scoped> автоматически помещает стили внутрь Shadow DOM:
<style scoped>
button {
  background-color: red;
}
</style>
  1. CSS Custom Properties Shadow DOM поддерживает переменные CSS, что позволяет передавать значения из внешнего контекста:
<style scoped>
p {
  color: var(--text-color, black);
}
</style>
  1. Стили через слоты Для элементов, вставленных через <slot>, можно использовать псевдокласс ::slotted:
<style scoped>
::slotted(span) {
  font-weight: bold;
}
</style>

Практические сценарии использования

  • Изоляция UI-библиотек: компоненты Vue с Shadow DOM предотвращают конфликты стилей между библиотеками.
  • Встраиваемые виджеты: можно создавать виджеты, которые легко вставлять в сторонние сайты без изменения глобального CSS.
  • Кастомные элементы: с опцией defineCustomElement компоненты Vue можно экспортировать как нативные Web Components с Shadow DOM.

Особенности работы с Vue 3

  • Поддержка Shadow DOM тесно связана с компиляцией компонентов. При использовании vite или webpack необходимо настроить правильную обработку стилей для shadow: true.
  • Внутренние хуки и реактивность Vue полностью сохраняются, Shadow DOM влияет только на рендер и стили, не нарушая реактивной системы.

Использование Shadow DOM в Vue.js позволяет создавать инкапсулированные, независимые компоненты с чистыми стилями и предсказуемым поведением. Комбинация слотов, CSS-переменных и событий с composed: true обеспечивает гибкость взаимодействия с внешним окружением при сохранении полной изоляции внутренней структуры компонента.