Die HTML-Webkomponente verwendet keinen Schatten-DOM-Stil

Aug 15 2020

Ich habe eine Vanille-Webkomponente oder ein HTML-Element erstellt. Es werden nur zwei Links angezeigt.

Um das Ding zu kapseln, benutze ich Shadow DOM. Es scheint jedoch nicht gekapselt zu sein. Im DOM-Baum befindet es sich in # shadow-root, was gut ist.

Warum verwendet die Webkomponente den globalen Stil anstelle des Stils, den ich in der Vorlage für meine Webkomponente angegeben habe?

Der Text ist rot und ich habe erwartet, dass er grün ist.

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>

Antworten

1 AlanDávalos Aug 17 2020 at 15:12

Während diese Frage bereits eine akzeptierte Antwort hat, ist es für die meisten Anwendungsfälle nicht wünschenswert, die untergeordneten Elemente eines Slots in den shadowRoot zu verschieben.

Was Sie wahrscheinlich tun möchten, ist die Verwendung des ::slotted()Selektors.

Denken Sie daran, dass Stile, die über die ::slotted()Auswahl auf die untergeordneten Elemente eines Slots angewendet werden, nur als "Standard" -Stile fungieren und dennoch durch die Verwendung von Stilen in Light DOM überschrieben werden können.

Überprüfen Sie beispielsweise diese bearbeitete Version Ihres Snippets:

Wie Sie sehen können, wird dieses Mal my-elversucht, sowohl einen Farb- als auch einen Textdekorationsstil auf verankerte ( <a>) Kinder in einem der Slots anzuwenden .

In Light Dom haben wir jedoch einen a.specialSelektor, der die Farbe überschreibt, sodass die Farbe <a class="special">rot und nicht grün ist

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>

1 Danny'365CSI'Engelman Aug 15 2020 at 23:44

Die vollständige, detaillierte Erklärung finden Sie in: :: CSS-Selektor mit Schlitz für verschachtelte Kinder im ShadowDOM-Slot

TL; DR

Ihre Links befinden sich in lightDOM und werden daher durch das DOM (in Ihrem Code das Dokument-DOM) gestaltet. Das
Verschieben der Knoten von lightDOM nach shadowDOM ist eine "Lösung". Dann verwenden Sie jedoch keine Slots.

Zu Ihrer Information, Ihr Code kann komprimiert werden zu:

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

  }
}

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

Weitere SLOT-bezogene Antworten finden Sie mit StackOverflow Search: Custom Elements SLOTs

KresimirPendic Aug 15 2020 at 19:57

Beachten Sie diese Linie, Sie müssen Elemente verschieben / kopieren, um sie zu schattieren, zum Beispiel mit:

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

Ich habe dies hinzugefügt, um zu demonstrieren, dass nur Inline-Stil auf Shadow-Dom-Elemente angewendet wird. Kopierte Links in SD verwenden also Ihren Stil :)

So wird Rot sein GLOBAL, Grün wird SHADOWElemente sein

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>