通过Shadow DOM(v1)示例in this tutorial,它定义了一个Web组件(标签),其中每个标签对应一个命名和默认的插槽:
<fancy-tabs>
<button slot="title">Title</button>
<button slot="title" selected>Title 2</button>
<button slot="title">Title 3</button>
<section>content panel 1</section>
<section>content panel 2</section>
<section>content panel 3</section>
</fancy-tabs>
它会呈现给你:
<fancy-tabs>
#shadow-root
<div id="tabs">
<slot id="tabsSlot" name="title">
<button slot="title">Title</button>
<button slot="title" selected>Title 2</button>
<button slot="title">Title 3</button>
</slot>
</div>
<div id="panels">
<slot id="panelsSlot">
<section>content panel 1</section>
<section>content panel 2</section>
<section>content panel 3</section>
</slot>
</div>
</fancy-tabs>
为了保留现有的API,我想创建一个类似于此的组件,但是我可以将每个Tab创建为自己的自定义元素。所以API看起来像:
<fancy-tabs>
<fancy-tab>
<button slot="title">Title</button>
<section>content panel 1</section>
</fancy-tab>
<fancy-tab>
<button slot="title" selected>Title 2</button>
<section>content panel 2</section>
<fancy-tab>
<fancy-tab>
<button slot="title" selected>Title 3</button>
<section>content panel 3</section>
<fancy-tab>
</fancy-tabs>
但是它会像上面那样呈现给类似的Shadow DOM。
换句话说,我想要的是像<fancy-tab>
这样的中间元素,同时仍然控制它下面的槽元素。我尝试将<fancy-tab>
创建为具有开放shadowRoot的CE,作为没有shadowRoot的CE,并且根本不将其定义为自定义元素。
有没有办法做到这一点?或者插槽有是Light DOM的第一个孩子吗?
答案 0 :(得分:1)
具有slot
属性的元素必须是Light DOM的第一个子元素。
因此,如果您想保留第3段代码的结构,可以使用nested custom elements,每个代码都带有影子DOM。
<fancy-tabs>
组件将获取<fancy-tab>
。
<fancy-tab>
组件将获取内容。
实际上要创建一个&#34;标签&#34;您甚至不必定义影子DOM的子组件(但当然可以用于定制需求)。
这是一个最小的<fancy-tabs>
自定义元素示例:
customElements.define( 'fancy-tabs', class extends HTMLElement
{
constructor()
{
super()
this.btns = this.querySelectorAll( 'button ')
this.addEventListener( 'click', this )
this.querySelector( 'button[selected]' ).focus()
}
handleEvent( ev )
{
this.btns.forEach( b =>
{
if ( b === ev.target )
b.setAttribute( 'selected', true )
else
b.removeAttribute( 'selected' )
} )
}
} )
&#13;
fancy-tabs {
position: relative ;
}
fancy-tab > button {
border: none ;
}
fancy-tab > section {
background: #eee ;
display: none ;
position: absolute ; left: 0 ; top: 20px ;
width: 300px ; height: 75px ;
}
fancy-tab > button[selected] + section {
display: inline-block ;
}
&#13;
<fancy-tabs>
<fancy-tab>
<button>Title 1</button>
<section>content panel 1</section>
</fancy-tab>
<fancy-tab>
<button selected>Title 2</button>
<section>content panel 2</section>
</fancy-tab>
<fancy-tab>
<button>Title 3</button>
<section>content panel 3</section>
</fancy-tab>
</fancy-tabs>
&#13;