Как реагировать на первую краску / макет после первоначального распределения слотов
У меня есть пользовательский элемент, my-el
, который в своем шаблоне DOM (теневой корень) содержит slot
элемент. На веб-странице я использую my-el
помещая дополнительные элементы между тегами <my-el>
</my-el>
как показано ниже.
<my-el>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</my-el>
Я намерен измерить div
Размеры s помещены в my-el
поскольку они находятся в распределенном дереве, как только (то есть в первый раз) они отображаются на странице. Согласно спецификации:
Чтобы назначить слоты, для слота слота с необязательным флагом подавления сигнализации (не установлен, если не указано иное) выполните следующие действия:
Пусть slotables будет результатом нахождения slotables для слота.
Если флаг подавления сигнализации не установлен, а временные интервалы и назначенные узлы слота не идентичны, то сигнал запуска изменяет интервал для слота.
...
Если я правильно понял, первое распределение слотов слотов не запускает slotchange
событие, поскольку флаг подавления сигнализации установлен, когда слот не выполнил начальное распределение, дополнительно заявлено в Shadow DOM v1: Автономные веб-компоненты. Это означает, что я не могу сделать начальное измерение дочерних элементов в обратном вызове slotchange
, Кроме того, следующий подход не гарантирует, что в этот момент дети будут воспроизведены:
connectedCallback() {
super.connectedCallback();
requestAnimationFrame(() => {
// Measure chilren
});
}
Вопрос
Как я могу запустить свои измерения при первом отображении их после распределения в slot
в my-el
?
1 ответ
Вы можете определить переменную в вашем пользовательском элементе, которая будет установлена при первом отображении ваших элементов (либо в connectedCallback
или в slotchange
событие).
Затем проверьте значение переменной, чтобы решить, будет ли это первый рендеринг.
customElements.define( 'c-e', class extends HTMLElement
{
connectedCallback ()
{
var sh = this.attachShadow( { mode: 'open' } )
sh.appendChild( T1.content.cloneNode( true ) )
sh.querySelector( 'button').onclick = ev =>
this.appendChild( document.createElement( 'div') ).innerHTML = 'new div'
sh.querySelector( 'slot' ).addEventListener( 'slotchange', ev =>
!len && ( len = this.render() ) )
var len = this.render()
}
render ()
{
var count = this.querySelectorAll( 'div' ).length
if ( count )
console.info( '%s elem. first rendered in %s', count, this.id )
return count
}
} )
<c-e id=CE1>
<div>div 1</div>
<div>div 2</div>
</c-e>
<c-e id=CE2>
</c-e>
<template id=T1>
<style>
:host {
display: inline-flex;
flex-direction: column;
width: 150px;
border: 1px solid lightblue;
min-height: 4em;
margin: 5px;
background: #f7f7f7;
}
</style>
<div>
<button>add div</button>
</div>
<slot>
</slot>
</template>