Когда вы добавляете shadowDOM, содержимое вашего элемента становится "lightDOM" ..
Это больше не отображается в основном DOM и не части вашего shadowDOM.
Как объяснил Supersharp в 2017 году :
Light DOM - это просто простое старое дерево DOM внутри элемента HTML.
Этот термин используется только в контексте веб-компонентов (пользовательских элементов с теневым DOM)
Полагаю, обычный DOM был переопределен как Light в отличие от Shadow .
Спецификации WHATWG называют его теневым root узлом дерева узлов или светлым деревом :
Добавлен Shadow DOM DOM, который восстанавливает, маскирует или заменяет обычный DOM,
, как описано в статье от Google .
Вы должны перенести контент lightDOM в shadowDOM самостоятельно:
customElements.define('my-element', class extends HTMLElement {
constructor() {
super()
//create shadowDOM (thus creating lightDOM) and append Template
this.attachShadow({mode: 'open'})
.append(document.getElementById(this.nodeName).content.cloneNode(true))
}
connectedCallback(){
//append content from lightDOM
this.shadowRoot.append(...this.querySelectorAll('DIV'));
}
})
my-element{
border: 1px dashed blue;
}
<template id="MY-ELEMENT">
<style>
:host {
display: block;
font-size:20px;
}
h4{
background:yellow;
margin: .5em 0;
}
div{
background:lightcoral;
}
</style>
<h4><slot name="title"></slot></h4>
</template>
<my-element>
<!-- begin lightDOM because my-element has shadowDOM -->
<span slot="title">whole SPAN is slotted</span>
<div>I am appended</div>
<div>appended too</div>
<p>I remain (invisible) in lightDOM</p>
<!-- end lightDOM -->
</my-element>
<my-element>
<!-- begin lightDOM because my-element has shadowDOM -->
<span slot="title">slotted too</span>
<div>appended again</div>
I remain (invisible) in lightDOM
<!-- end lightDOM -->
</my-element>
Примечания к фрагменту:
Шаблон клонирован
append в connectedCallback
перемещает содержимое,
, если вы хотите оставить оригинал в lightDOM ( например, использовать его как хранилище данных)
вы должны клонировать его, как это было сделано с template
.
slot="title"
ходов всего span
(включая пролет!) В свой слот в shadowDOM
Попробуйте сами:
На игровой площадке JSFiddle: https://jsfiddle.net/CustomElementsExamples/bzvLcxfe/
Будьте в курсе! Браузеры ведут себя по-разному!
Вы можете требовать a setTimeout
в connectedCallback
, когда (основной) DOM еще не был создан:
connectedCallback() {
let savedHTML = this.outerHTML;
//append content from lightDOM
const append = (selector) =>
this.shadowRoot.append(...this.querySelectorAll(selector), savedHTML);
if (this.outerHTML.includes("timeout"))
setTimeout(() => append('DIV'))
else
append('DIV');
}
JSFiddle детская площадка: https://jsfiddle.net/CustomElementsExamples/bzvLcxfe/
в первый желтый Элемент DIV добавлен без a setTimeout
в секунду желтый элемент DIV добавляется с a setTimeout
outerHTML
(известный в connectedCallback
) добавляется в оба элемента.
Результат ( Chromium ) Chrome \ Edge \ Opera:
- lightDOM недоступно доступно,
setTimeout
требуется для задержки кода до завершения события l oop и доступности lightDOM.
Результат в ( Gecko ) FireFox:
- lightDOM доступно доступно, нет
setTimeout
требуется
Результат в Safari:
- Не знаю (пока ), пожалуйста, дайте мне знать
Примечания:
Это происходит (в браузерах Chromium), когда customElements.define
запускается до ваш DOM готов. Если вы измените JSFiddle и выполните блок <script>
после элементов DOM, все в порядке.
(но большую часть времени вы загружаете библиотеки как можно скорее, чтобы предотвратить FOUCs
requestAnimationFrame
в connectedCallback
имеет то же поведение, что и setTimeout
. Подробнее: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
ваш DOM может также будет готов при загрузке ваших элементов asyn c
<script src=elements.js async ></script>