考虑以下代码:

//js
class FooBar extends HTMLElement {
  constructor(){
    super();
  }
}

customElements.define('foo-bar', FooBar);


<!-- html -->
<foo-bar>
  <h1>Test</h1>
</foo-bar>

这将在浏览器中显示»Test«。

如果构造函数更改为:
constructor () {
  super();
  this.shadow = this.attachShadow({ mode: 'open' })
}

»Test«消失了,因为现在有一个影子根了。

如果构造函数进一步更改为
constructor () {
  super();
  this.shadow = this.attachShadow({ mode: 'open' });
  this.shadow.appendChild(document.createElement('slot'));
}

再次出现»Test«,因为现在<foo-bar>的所有子节点都有一个默认插槽

但是,如果影子根目录中没有<slot />,子节点会发生什么情况。它们仍然出现在this.children中,并且其style.display属性仍然是""。所以它们在dom之内,却未被渲染,即使您讲相反的话?这里到底发生了什么?

最佳答案

完整的详细解释在:::slotted CSS selector for nested children in shadowDOM slot

<foo-bar>
  <h1>Test</h1>
</foo-bar>
H1是 lightDOM
“添加” shadowDOM/root 内容是反射(reflect)了 shadowDOM ,没有移动!
H1始终保留在lightDOM中:
  • lightoji 中的
  • (在页面中)的隐含(在页面中),带有 shadowDOM/root的元素
  • 自定义元素的可见(在页面中),而没有 shadowDOM/root
  • ,除非您使用appendChild(或任何DOM移动操作)显式移动它

  • 您说:所以它们在dom之内,但没有呈现,即使CSS告诉您相反的情况?
    不,它们呈现的,就像任何普通的DOM元素一样。只是不再可见。
    您可以通过在lightDOM中包含一个SCRIPT标记来进行测试。它会渲染并执行!

    在下面的代码段中
    您使用this.querySelector("span").innerHTML="weird";引用 lightDOM
    但是用this.shadowRoot.querySelector("span").innerHTML="weird";引用 shadowDOM
    不起作用不起作用,因为DIV(带有SPAN)位于中的黑盒

    <template id="MY-ELEMENT">
      <style>
        :host {
          display: inline-block;
          font-family: Arial;
        }
        ::slotted(div){
          color:blue;
        }
        ::slotted(span){
          color:gold; /* alas, you can style the 'box', not elements inside */
        }
      </style>
      <h3><slot></slot></h3>
    </template>
    <style>
      span {
        background:lightcoral; /* from global/host CSS, style slotted content lightDOM */
      }
    </style>
    <script>
      customElements.define('my-element', class extends HTMLElement {
        constructor() {
          super().attachShadow({mode: 'open'})
                 .append(document.getElementById(this.nodeName).content.cloneNode(true));
        }
      });
    </script>
    <my-element>
      <div>Hello <span>Component</span> World!</div>
    </my-element>

    检查F12开发工具中的组件:
    Chrome和Firefox:

    DIV不在shadowDOM/根目录中,在lightDOM中保持不可见
    所有元素/样式都将始终反射(reflect)到shadowDOM/root
    点击“显示”将您带到lightDOM

    注意:在F12控制台中编辑DIV,您将立即看到更改反射(reflect)到shadowDOM

    SLOTs和lightDOM是实时连接
    通过更改<slot name=...>,您可以进行交互(想想路线,选项卡,答案),而以前需要更多的编码(还记得那些jQuery显示/隐藏天数吗?)

    <template id="MY-ELEMENT">
      Custom Element SLOTs are:
      <slot name=answer></slot>
    </template>
    <style>
      img { /* style all IMGs in lightDOM */
        max-width: 100vw;
        max-height: 70vh;
      }
    </style>
    <script>
      customElements.define('my-element', class extends HTMLElement {
        connectedCallback() {
          this.attachShadow({mode: 'open'})
              .append(document.getElementById(this.nodeName).content.cloneNode(true));
          this.onclick = (evt) => {
               const answer = evt.composedPath()[0].innerText; // button label
               this.shadowRoot.querySelector('slot').name = answer;
               this.children[0].slot = answer;//include lightDOM buttons again
          }
        }
      });
    </script>
    <my-element>
      <span slot=answer><button>Cool</button><button><b>Awesome</b></button><button>Great</button></span>
      <div slot=Cool><img src="https://i.imgur.com/VUOujQT.jpg"></div>
      <span slot=Awesome> <h3>SUPER!</h3></span>
      <div slot=Awesome><img src="https://i.imgur.com/y95Jq5x.jpg"></div>
      <div slot=Great><img src="https://i.imgur.com/gUFZNQH.jpg"></div>
    </my-element>


    可通过StackOverflow搜索找到更多与SLOT相关的答案:Custom Elements SLOTs

    09-28 00:39