如果我中间有一个中间元素,我可以插入Shadow DOM内容吗?

时间:2017-03-06 22:48:15

标签: web-component shadow-dom

通过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的第一个孩子吗?

1 个答案:

答案 0 :(得分:1)

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

因此,如果您想保留第3段代码的结构,可以使用nested custom elements,每个代码都带有影子DOM。

<fancy-tabs>组件将获取<fancy-tab><fancy-tab>组件将获取内容。

实际上要创建一个&#34;标签&#34;您甚至不必定义影子DOM的子组件(但当然可以用于定制需求)。

这是一个最小的<fancy-tabs>自定义元素示例:

&#13;
&#13;
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;
&#13;
&#13;