如何在初始插槽分配后对第一个 paint/layout 做出反应
How to react on first paint/layout after initial slot distribution
我有一个自定义元素 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
中放置在 my-el
中的尺寸,因为它们在分布式树中,尽快 (即第一个时间)它们呈现在页面上。根据 spec:
To assign slotables, for a slot slot with an optional suppress signaling flag (unset unless stated otherwise), run these steps:
Let slotables be the result of finding slotables for slot.
If suppress signaling flag is unset, and slotables and slot’s assigned nodes are not identical, then run signal a slot change for slot.
...
如果我没理解错的话,插槽表的第一次分发不会触发 slotchange
事件,因为 抑制信号标志 在插槽未执行时设置初始分布,在 中进一步说明
Shadow DOM v1:独立的 Web 组件 。这意味着我无法在 slotchange
的回调中对子元素进行初始测量。此外,以下方法不能保证在那时将呈现子项:
connectedCallback() {
super.connectedCallback();
requestAnimationFrame(() => {
// Measure chilren
});
}
问题
如何在 my-el
中的 slot
中分发后第一次呈现时触发我的测量?
您可以在您的自定义元素中定义一个变量,该变量将在您的元素首次呈现时设置(在 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>
我有一个自定义元素 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
中放置在 my-el
中的尺寸,因为它们在分布式树中,尽快 (即第一个时间)它们呈现在页面上。根据 spec:
To assign slotables, for a slot slot with an optional suppress signaling flag (unset unless stated otherwise), run these steps:
Let slotables be the result of finding slotables for slot.
If suppress signaling flag is unset, and slotables and slot’s assigned nodes are not identical, then run signal a slot change for slot.
...
如果我没理解错的话,插槽表的第一次分发不会触发 slotchange
事件,因为 抑制信号标志 在插槽未执行时设置初始分布,在 中进一步说明
Shadow DOM v1:独立的 Web 组件 。这意味着我无法在 slotchange
的回调中对子元素进行初始测量。此外,以下方法不能保证在那时将呈现子项:
connectedCallback() {
super.connectedCallback();
requestAnimationFrame(() => {
// Measure chilren
});
}
问题
如何在 my-el
中的 slot
中分发后第一次呈现时触发我的测量?
您可以在您的自定义元素中定义一个变量,该变量将在您的元素首次呈现时设置(在 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>