Komponent sieciowy HTML nie używa stylu shadow DOM

Aug 15 2020

Stworzyłem waniliowy komponent sieciowy lub element HTML. Wyświetla tylko dwa łącza.

Aby zamknąć to, używam Shadow DOM. Jednak nie wydaje się, aby był zamknięty. W drzewie DOM jest wewnątrz # shadow-root, co jest dobre.

Dlaczego komponent sieciowy używa stylu globalnego zamiast stylu podanego w szablonie dla mojego komponentu WWW?

Tekst jest czerwony i spodziewałem się, że będzie zielony.

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>

Odpowiedzi

1 AlanDávalos Aug 17 2020 at 15:12

Chociaż to pytanie ma już zaakceptowaną odpowiedź, przeniesienie elementów potomnych gniazda do shadowRoot nie jest pożądane w większości przypadków użycia.

Prawdopodobnie chcesz użyć ::slotted()selektora.

Pamiętaj tylko, że style zastosowane do elementów podrzędnych boksu za pomocą ::slotted()selektora działają tylko jako style „domyślne” i nadal można je przesłonić, używając stylów w lekkim DOM.

Na przykład sprawdź tę edytowaną wersję swojego fragmentu:

Jak widać, tym razem my-elpróbuje zastosować kolor i styl dekoracji tekstu do elementów <a>potomnych anchor ( ) w dowolnym ze swoich gniazd.

Jednak w light dom mamy a.specialselektor, który zastępuje kolor, więc <a class="special">będzie czerwony, a nie zielony

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

Pełne, szczegółowe wyjaśnienie znajduje się w: :: slotted CSS selector dla zagnieżdżonych dzieci w slocie shadowDOM

TL; DR

Twoje linki znajdują się w lightDOM i dlatego są stylizowane na DOM (w twoim kodzie dokument DOM)
Przeniesienie węzłów z lightDOM do shadowDOM jest jednym "rozwiązaniem"; ale wtedy nie używasz slotów.

FYI, twój kod można skompaktować do:

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

  }
}

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

Więcej odpowiedzi związanych z SLOTami można znaleźć w wyszukiwarce StackOverflow: Boksy na elementy niestandardowe

KresimirPendic Aug 15 2020 at 19:57

obserwuj tę linię, musisz przenieść / skopiować elementy do cienia, na przykład za pomocą:

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

Dodałem to, aby zademonstrować, że tylko styl wbudowany zostanie zastosowany do elementów shadow dom ... więc skopiowane linki w SD używają Twojego stylu :)

więc czerwony będzie GLOBAL, zielony będzie SHADOWelementami

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>