Как реагировать на первую краску / макет после первоначального распределения слотов

У меня есть пользовательский элемент, 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 поскольку они находятся в распределенном дереве, как только (то есть в первый раз) они отображаются на странице. Согласно спецификации:

Чтобы назначить слоты, для слота слота с необязательным флагом подавления сигнализации (не установлен, если не указано иное) выполните следующие действия:

  1. Пусть slotables будет результатом нахождения slotables для слота.

  2. Если флаг подавления сигнализации не установлен, а временные интервалы и назначенные узлы слота не идентичны, то сигнал запуска изменяет интервал для слота.

...

Если я правильно понял, первое распределение слотов слотов не запускает 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>

Другие вопросы по тегам