Shadow DOM - garevna/js-course GitHub Wiki

🎓 Shadow DOM

До появления Shadow DOM инкапсуляция стилей элементов DOM была острой проблемой разработчиков

Однако с учетом поддержки Shadow DOM всеми основными браузерами эта проблема больше не существует

Shadow DOM - это суверенное дерево DOM-узлов элемента

Shadow DOM API обеспечивает возможность привязать Shadow DOM к отдельному элементу

Термины:
🔹 Shadow host - элемент DOM, к которому привязан shadow DOM
🔹 Shadow tree - дерево элементов DOM внутри shadow DOM
🔹 Shadow boundary - граница между shadow DOM и обычным DOM
🔹 Shadow root - корневой элемент дерева shadow DOM

Оперировать элементами shadow DOM можно точно так же, как и обычными DOM элементами:

можно добавлять дочерние элементы или атрибуты настройки,
стилизовывать отдельные узлы с помощью element.style
или применять стили ко всему дереву shadow DOM внутри элемента <style>

Преимущество заключается в том, что содержимое shadow DOM инкапсулировано внутри него, и не может отразиться на поведении или стилях других элементов DOM

Кроме того, все свойства элемента, "спрятанные" в его shadow DOM, не могут быть случайно изменены извне


🎓 attachShadow()

Добавить элементу его собственный shadow DOM очень легко
Для этого существует метод attachShadow()
Метод attachShadow() принимает в качестве аргумента объект опций, который содержит единственную опцию mode
Опция mode может иметь значение 'open' или 'closed'

const elem = document.createElement('div')
elem.attachShadow({ mode: 'open' })

☕ 1️⃣

const elem = document.body.appendChild(document.createElement('div'))
const shadow = elem.attachShadow({ mode: 'open' })
shadow.appendChild(Object.assign(document.createElement('script'), {
  innerText: `console.log('HELLO!')`
}))
shadow.appendChild(Object.assign(document.createElement('img'), {
  src: 'http://www.radioactiva.cl/wp-content/uploads/2018/05/pikachu.jpg'
}))
shadow.appendChild(Object.assign(document.createElement('style'), {
  textContent: 'img { width: 200px; }'
}))

mode: 'open'

Значение 'open' означает, что shadow DOM данного элемента будет доступен в контексте страницы через его свойство shadowRoot

<div>
  ▼ #shadow-root ( open )
       <img src="http://www.radioactiva.cl/wp-content/uploads/2018/05/pikachu.jpg">
       <style>img { width: 200px; }</style>
</div>
Доступные свойства shadowRoot
console.dir(elem.shadowRoot)
▼ #document-fragment
    activeElement: null
    baseURI: "about:blank"
    childElementCount: 2
  ► childNodes: NodeList(2) [img, style]
  ► children: HTMLCollection(2) [img, style]
    delegatesFocus: false
  ► firstChild: img
  ► firstElementChild: img
  ► host: div
    innerHTML: "<img src="http://www.radioactiva.cl/wp-content/uploads/2018/05/pikachu.jpg"><style>img { width: 200px; } 
    </style>"
    isConnected: true
  ► lastChild: style
  ► lastElementChild: style
    mode: "open"
    nextSibling: null
    nodeName: "#document-fragment"
    nodeType: 11
    nodeValue: null
  ► ownerDocument: document
    parentElement: null
    parentNode: null
    pictureInPictureElement: null
    pointerLockElement: null
    previousSibling: null
  ► styleSheets: StyleSheetList {0: CSSStyleSheet, length: 1}
    textContent: "img { width: 200px; }"
  ► __proto__: ShadowRoot

mode: 'closed'

Значение 'closed' делает shadow DOM данного элемента недоступным для скриптов

При обращении к свойству shadowRoot элемента будет возвращено значение null

Доступные свойства shadowRoot
console.dir(elem.shadowRoot)
null

### 💼 Упражнения

⚠️ **GitHub.com Fallback** ⚠️