Перемещение элемента из светлого DOM в ShadowDOM без отсоединения
Интересно, нахожусь ли я на правильном пути здесь
Цель: необходимо убедиться, что все элементы попадают в shadowDOM
Таким образом, созданный вручную HTML-файл
<cardts-pile>
<cardts-card>A</cardts-card>
<cardts-card>B</cardts-card>
</cardts-pile>
создает карты в свете DOM <cardts-pile>
если я затем переместить их в shadowDOM (конечно):
► <cardts-card>
удаляется из DOM (запуск disconnectedCallback()
)
► <cardts-card>
добавляется снова (запуск connectedCallback()
)
[см. console.log для запуска Code Snipper ниже]
У меня есть более необычный код в card.connectedCallback()
при повторном подключении это в основном вызывает тот же самый код снова.
Вопросы
Можно ли перемещать узлы без изменений DOM?
Есть ли OOTB-код, чтобы проверить, существует ли
<cardts-card>
только перемещается,
такconnectedCallback
знает, что не нужно снова запускать код.Должен ли я делать что-то другое,
сделать так, чтобы эти элементы lightDOM сразу оказались в shadowDOM?
customElements.define('cardts-pile', class extends HTMLElement {
constructor(){
super();
this.attachShadow({mode: 'open'}).innerHTML='<slot></slot>';
}
connectedCallback() {
console.log('connect pile');
}
});
customElements.define('cardts-card', class extends HTMLElement {
constructor(){
super();
this.attachShadow({mode: 'open'}).innerHTML='<slot></slot>';
}
connectedCallback() {
console.log('connect card',this.innerText);
if (!this.getRootNode().host) // not in shadowDOM
this.parentNode.shadowRoot.insertBefore(this,null);//or appendChild
}
disconnectedCallback() {
console.log('disconnect card',this.innerText);
}
});
<cardts-pile>
<cardts-card>A</cardts-card>
<cardts-card>B</cardts-card>
</cardts-pile>
1 ответ
Можно ли перемещать узлы без изменений DOM?
Нет (насколько я знаю о Shadow DOM).
Есть ли код OOTB, чтобы проверить, перемещается ли существующий только?
Я бы использовал логический флаг:
connectedCallback() {
if ( !this.connected )
console.log( 'creation' )
else {
console.log( 'move' )
this.connected = true
}
(или в disconnectedCallack
)
customElements.define('cardts-pile', class extends HTMLElement {
constructor(){
super();
this.attachShadow({mode: 'open'}).innerHTML='<slot></slot>';
this.shadowRoot.addEventListener( 'slotchange', ev => {
let node = this.querySelector( 'cardts-card' )
node && this.shadowRoot.append( node )
})
}
connectedCallback() {
console.log('connect pile');
}
});
customElements.define('cardts-card', class extends HTMLElement {
constructor(){
super();
this.attachShadow({mode: 'open'}).innerHTML='<slot></slot>';
}
connectedCallback() {
if ( !this.connected )
console.log( this.innerText + ' created' )
else
console.log( this.innerText + ' moved' )
this.connected = true
}
disconnectedCallback() {
if ( !this.moved )
console.log( 'moving ' + this.innerText );
else
console.log( 'really disconnected' )
this.moved = true
}
});
<cardts-pile>
<cardts-card>A</cardts-card>
<cardts-card>B</cardts-card>
</cardts-pile>
Должен ли я делать что-то другое?
Вы можете вместо этого определить или обновить <cardts-card>
только после перемещения неизвестных элементов, если это возможно, хотя я не думаю, что это хорошая практика, если вы не можете контролировать все время выполнения, например, с помощью whenDefined()
или с заказанным HTML и кодом Javascript:
customElements.define('cardts-pile', Pile)
customElements.whenDefined('cardts-pile').then(() =>
customElements.define('cardts-card', Card)
)
В приведенном ниже примере вы определяете класс Pile
до или после занятий Card
(в зависимости от того, как они связаны).
class Card extends HTMLElement {
constructor(){
super()
this.attachShadow({mode: 'open'}).innerHTML='<slot></slot>'
}
connectedCallback() {
console.log(this.innerText + ' connected')
}
disconnectedCallback() {
console.log(this.innerText + ' disconnected')
}
}
class Pile extends HTMLElement {
constructor() {
super()
this.attachShadow({mode: 'open'})
}
connectedCallback() {
console.log('connect pile')
this.shadowRoot.append(...this.querySelectorAll('cardts-card'))
}
}
window.onload = () => customElements.define('cardts-pile', Pile)
customElements.whenDefined('cardts-pile').then(() =>
customElements.define('cardts-card', Card)
)
<cardts-pile>
<cardts-card>A</cardts-card>
<cardts-card>B</cardts-card>
</cardts-pile>