【问题标题】:HTML web component does not use shadow DOM styleHTML web 组件不使用 shadow DOM 样式
【发布时间】:2020-12-05 02:59:31
【问题描述】:

我创建了一个普通的 Web 组件或 HTML 元素。它只显示两个链接。

为了封装这个东西,我使用了 shadow DOM。但是,它似乎没有被封装。在 DOM 树中,它位于 #shadow-root 内部,这很好。

为什么 Web 组件使用全局样式而不是我在模板中为我的 Web 组件提供的样式?

文本是红色的,我希望它是绿色的。

class MyEl extends HTMLElement {
  constructor() {
    super();
    this.shadow = this.attachShadow({ mode: "open" });
  }

  connectedCallback() {
    const template = `
      <style>
        a {
          color: green;
        }
      </style>
      <slot></slot>`;
    this.shadow.innerHTML = template;
  }
}

window.customElements.define("my-el", MyEl);
a {
  color: red
}
  <my-el>
    <a href="example.com">Item1</a>
    <a href="example.com">Item2</a>
  </my-el>

【问题讨论】:

标签: javascript html web-component custom-element


【解决方案1】:

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

TL;DR

您的链接位于 lightDOM 中,因此由其 DOM 设置样式(在您的代码中为文档 DOM)
将节点从 lightDOM 移动到 shadowDOM 是一种“解决方案”;但那时你没有使用插槽。

仅供参考,您的代码可以压缩为:

class MyEl extends HTMLElement {
  constructor() {
    super().attachShadow({ mode: "open" })
           .innerHTML = `<style>a{color:green}</style><slot></slot>`;

  }
}

window.customElements.define("my-el", MyEl);

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

【讨论】:

    【解决方案2】:

    虽然这个问题已经有一个公认的答案,但对于大多数用例来说,将插槽的子级移动到 shadowRoot 是不可取的。

    您可能想要做的是使用::slotted() 选择器。

    请记住,通过 ::slotted() 选择器应用于插槽子项的样式仅充当“默认”样式,并且仍然可以通过在轻量级 DOM 中使用样式来覆盖。

    例如,检查你的 sn-p 的这个编辑版本:

    如您所见,这次my-el 尝试同时应用颜色和文本装饰样式来锚定 (&lt;a&gt;) 任何插槽中的子级。

    但是,在 light dom 中,我们有一个覆盖颜色的 a.special 选择器,因此 &lt;a class="special"&gt; 将是红色,而不是绿色

    class MyEl extends HTMLElement {
      constructor() {
        super();
        this.shadow = this.attachShadow({ mode: "open" });
      }
    
      connectedCallback() {
        const template = `
          <style>
            ::slotted(a) {
              color: green;
              text-decoration: none;
            }
          </style>
          <slot></slot>`;
        this.shadow.innerHTML = template;
      }
    }
    
    window.customElements.define("my-el", MyEl);
    a.special {
      color: red
    }
      <my-el>
        <a href="example.com">Item1</a>
        <a class="special" href="example.com">Item2</a>
      </my-el>

    【讨论】:

      【解决方案3】:

      请注意这一行,您必须将元素移动/复制到阴影中,例如:

      this.shadow.innerHTML = this.innerHTML + template;
      

      我已经添加了这个来证明只有内联样式将应用于阴影 dom 元素..所以 SD 中复制的链接正在使用您的样式:)

      所以 red 将是 GLOBALgreen 将是 SHADOW 元素

      class MyEl extends HTMLElement {
        constructor() {
          super();
        }
      
        connectedCallback() {
          this.shadow = this.attachShadow({ mode: "open" });
          const template = `
            <style>
              a {
                color: green;
              }
            </style>
            <slot></slot>`;
          this.shadow.innerHTML = this.innerHTML + template;
        }
      }
      
      window.customElements.define("my-el", MyEl);
      a {
        color: red
      }
      <my-el>
          <a href="example.com">Item1</a>
          <a href="example.com">Item2</a>
        </my-el>

      【讨论】:

        猜你喜欢
        • 2020-03-03
        • 1970-01-01
        • 1970-01-01
        • 2023-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-14
        • 1970-01-01
        相关资源
        最近更新 更多