首页 文章

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

提问于
浏览
3

通过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> 这样的中间元素,同时仍然控制它下面的槽元素 . 我尝试使用开放的shadowRoot创建 <fancy-tab> 作为CE,作为没有shadowRoot的CE,并且根本不将其定义为自定义元素 .

Is there a way to do this? 或者插槽必须是Light DOM的第一个孩子吗?

1 回答

  • 1

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

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

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


    实际上,要创建一个“tabs”组件,您甚至不必定义shadow 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>
    

相关问题