如果没有`<slot />`,但是有影子根,子节点会发生什么

phi*_*ipp 6 javascript web-component custom-element

考虑这个代码:

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

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


<!-- html -->
<foo-bar>
  <h1>Test</h1>
</foo-bar>
Run Code Online (Sandbox Code Playgroud)

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

如果构造函数改为:

constructor () {
  super();
  this.shadow = this.attachShadow({ mode: 'open' }) 
}
Run Code Online (Sandbox Code Playgroud)

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

如果构造函数进一步更改为

constructor () {
  super();
  this.shadow = this.attachShadow({ mode: 'open' });
  this.shadow.appendChild(document.createElement('slot')); 
}
Run Code Online (Sandbox Code Playgroud)

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

但是如果<slot />影子根中没有子节点会发生什么。他们仍然出现在里面this.children并且它的style.display财产仍然存在""。所以他们在 dom 内,但没有被渲染,即使你 thr css 告诉相反?这里究竟发生了什么?

Dan*_*man 5

完整的详细解释位于::: slotted CSS 选择器用于在shadowDOM 槽中嵌套子项


<foo-bar>
  <h1>Test</h1>
</foo-bar>
Run Code Online (Sandbox Code Playgroud)

H1是lightDOM
“添加”shadowDOM/root <SLOT>内容被反射shadowDOM,而不是移动!

H1 始终保留在 lightDOM 中:

  • 对于具有ShadowDOM/root 的元素,在lightDOM中不可见(在页面中) ,

  • 对于没有ShadowDOM/root 的自定义元素可见(在页面中)

  • appendChild除非你使用(或任何 DOM 移动操作)显式移动它

你说:所以它们在 dom 内,但没有渲染,即使你的 CSS 告诉相反?

不,它们渲染,就像任何普通的 DOM 元素一样。只是不再可见了。

您可以通过在 lightDOM 中包含 SCRIPT 标签来进行测试..它将渲染并执行!


在下面的代码片段中

您引用lightDOMthis.querySelector("span").innerHTML="weird";

但是引用shadowDOMthis.shadowRoot.querySelector("span").innerHTML="weird";

不起作用因为 DIV(内部有 SPAN)被黑盒装在 <SLOT> 中

<foo-bar>
  <h1>Test</h1>
</foo-bar>
Run Code Online (Sandbox Code Playgroud)

在F12开发工具中检查组件:

Chrome 和火狐浏览器:

DIV 不在 ShadowDOM/root 中,在 lightDOM 中保持不可见
,所有元素/样式将始终反映到 ShadowDOM/root

单击“reveal”将您带到 lightDOM

所以对于ShadowDOM 来说,开槽内容是元素和样式的黑匣子;从 lightDOM
反射
,这就是为什么::slotted只能设置盒子的样式,而不是里面的内容。

注意:在 F12 控制台中编辑该 DIV,您将看到更改立即反映到 ShadowDOM


SLOT 和 lightDOM 是实时连接

通过更改,<slot name=...>您可以进行交互(想想路由、选项卡、答案),而以前需要更多的编码(还记得那些 jQuery 显示/隐藏的日子吗?)

<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>
Run Code Online (Sandbox Code Playgroud)


更多与 SLOT 相关的答案可以通过 StackOverflow 搜索找到:自定义元素 SLOT