Il componente web HTML non utilizza lo stile DOM shadow

Aug 15 2020

Ho creato un componente web vanilla o un elemento HTML. Visualizza solo due collegamenti.

Per incapsulare la cosa, utilizzo shadow DOM. Tuttavia non sembra essere incapsulato. Nell'albero DOM è all'interno di # shadow-root, il che è positivo.

Perché il componente Web utilizza lo stile globale anziché lo stile fornito nel modello per il componente Web?

Il testo è rosso e mi aspettavo che fosse verde.

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>

Risposte

1 AlanDávalos Aug 17 2020 at 15:12

Sebbene questa domanda abbia già una risposta accettata, spostare i figli di uno slot in shadowRoot non è desiderabile per la maggior parte dei casi d'uso.

Quello che probabilmente vuoi fare è usare il ::slotted()selettore.

Tieni presente che gli stili applicati ai figli di uno slot tramite il ::slotted()selettore agiscono solo come stili "predefiniti" e possono ancora essere sovrascritti utilizzando gli stili in DOM chiaro.

Ad esempio, controlla questa versione modificata del tuo snippet:

Come puoi vedere, questa volta my-elcerca di applicare sia uno stile di colore che uno stile di decorazione del testo ai <a>bambini anchor ( ) in uno qualsiasi dei suoi slot.

Tuttavia, in luce dom, abbiamo un a.specialselettore che sovrascrive il colore, quindi <a class="special">sarà rosso, non verde

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

La spiegazione completa e dettagliata è in: :: selettore CSS con slot per i figli nidificati nello slot shadowDOM

TL; DR

I tuoi link sono in lightDOM e quindi con lo stile del suo DOM (nel tuo codice il documento DOM)
Spostare i nodi da lightDOM a shadowDOM è una "soluzione"; ma allora non stai usando gli slot.

Cordiali saluti, il tuo codice può essere compattato in:

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

  }
}

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

Altre risposte relative a SLOT possono essere trovate con StackOverflow Search: Custom Elements SLOTs

KresimirPendic Aug 15 2020 at 19:57

osserva questa linea, devi spostare / copiare elementi in ombra ad esempio con:

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

Ho aggiunto questo per dimostrare che solo lo stile inline verrà applicato agli elementi shadow dom .. quindi i collegamenti copiati in SD stanno usando il tuo stile :)

quindi il rosso sarà GLOBAL, il verde sarà gli SHADOWelementi

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>