【问题标题】:Can I have slotted Shadow DOM content if I have an intermediate element in between?如果我在中间有一个中间元素,我可以插入 Shadow DOM 内容吗?
【发布时间】:2017-07-26 23:56:13
【问题描述】:

通过 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>

但是让它渲染到与上面类似的 Shadow DOM。

换句话说,我想要的是像&lt;fancy-tab&gt; 这样的中间元素,同时仍然控制它下面的槽元素。我尝试将 &lt;fancy-tab&gt; 创建为具有开放 shadowRoot 的 CE,作为没有 shadowRoot 的 CE,并且根本不将其定义为自定义元素。

有没有办法做到这一点?或者槽必须位于 Light DOM 的第一个子节点?

【问题讨论】:

    标签: web-component shadow-dom


    【解决方案1】:

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

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

    &lt;fancy-tabs&gt; 组件将获取&lt;fancy-tab&gt;&lt;fancy-tab&gt; 组件将抓取内容。


    实际上,要创建一个“选项卡”组件,您甚至不必定义 shadow DOM 的子组件(但您当然可以满足自定义需求)。

    这是一个最小的&lt;fancy-tabs&gt; 自定义元素示例:

    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>

    【讨论】:

      猜你喜欢
      • 2018-08-14
      • 1970-01-01
      • 2014-10-02
      • 2019-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-01
      • 2021-09-10
      相关资源
      最近更新 更多