如果中间有一个中间元素,我可以插入 Shadow DOM 内容吗?
Can I have slotted Shadow DOM content if I have an intermediate element in between?
通过 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,我想创建一个与此类似的组件,但我可以在其中创建每个选项卡作为其自己的自定义元素。所以 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>
但是让它渲染成与上面类似的阴影 DOM。
换句话说,我想要的是像 <fancy-tab>
这样的中间元素,同时仍然控制它下面的插槽元素。我已经尝试将 <fancy-tab>
创建为具有开放 shadowRoot 的 CE,创建为没有 shadowRoot 的 CE,并且根本不将其定义为自定义元素。
有没有办法做到这一点? 或者插槽 有 位于光的第一个 child DOM?
具有 slot
属性的元素必须是 Light DOM.
的第一个子元素
所以如果你想保留你的第三段代码的结构,你可以使用 ,每个都有阴影 DOM.
<fancy-tabs>
组件将获取 <fancy-tab>
。
<fancy-tab>
组件将抓取内容。
实际上,要创建一个 "tabs" 组件,您甚至不必定义影子的子组件 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' )
} )
}
} )
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 ;
}
<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>
通过 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,我想创建一个与此类似的组件,但我可以在其中创建每个选项卡作为其自己的自定义元素。所以 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>
但是让它渲染成与上面类似的阴影 DOM。
换句话说,我想要的是像 <fancy-tab>
这样的中间元素,同时仍然控制它下面的插槽元素。我已经尝试将 <fancy-tab>
创建为具有开放 shadowRoot 的 CE,创建为没有 shadowRoot 的 CE,并且根本不将其定义为自定义元素。
有没有办法做到这一点? 或者插槽 有 位于光的第一个 child DOM?
具有 slot
属性的元素必须是 Light DOM.
所以如果你想保留你的第三段代码的结构,你可以使用
<fancy-tabs>
组件将获取 <fancy-tab>
。
<fancy-tab>
组件将抓取内容。
实际上,要创建一个 "tabs" 组件,您甚至不必定义影子的子组件 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' )
} )
}
} )
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 ;
}
<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>