通过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作为其自己的Custom Element。因此,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>,同时仍控制其下面的slot元素。我尝试将<fancy-tab>创建为带有开放shadowRoot的CE,作为没有shadowRoot的CE,并且根本没有将其定义为自定义元素。

有办法吗? 还是插槽必须位于Light DOM的第一个子节点上?

最佳答案

具有slot属性的元素必须是Light DOM的第一个子元素。

因此,如果您想保留第三段代码的结构,可以使用nested custom elements,每个都有影子DOM。
<fancy-tabs>组件将抓取<fancy-tab><fancy-tab>组件将获取内容。

实际上,创建“选项卡”组件甚至不必定义影子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>

关于web-component - 如果我之间有一个中间元素,是否可以插入Shadow DOM内容?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42637052/

10-17 02:58