Stínový DOM

Shadow DOM slouží k zapouzdření. Umožňuje komponentě mít svůj vlastní „stínový“ strom DOM, ke kterému nelze náhodně přistupovat z hlavního dokumentu, může mít pravidla místního stylu a další.

Vestavěný stínový DOM

Přemýšleli jste někdy o tom, jak složité ovládací prvky prohlížeče jsou vytvářeny a stylizovány?

Například <input type="range"> :

Prohlížeč k jejich vykreslování používá interně DOM/CSS. Tato struktura DOM je před námi běžně skrytá, ale můžeme ji vidět ve vývojářských nástrojích. Např. v Chrome musíme v nástrojích pro vývojáře povolit možnost „Zobrazit stínový DOM uživatelského agenta“.

Poté <input type="range"> vypadá takto:

Co vidíte pod #shadow-root se nazývá „shadow DOM“.

Nemůžeme získat vestavěné stínové prvky DOM běžnými voláními nebo selektory JavaScriptu. Nejsou to běžné děti, ale výkonná technika zapouzdření.

Ve výše uvedeném příkladu můžeme vidět užitečný atribut pseudo . Je to nestandardní, existuje z historických důvodů. Můžeme použít dílčí prvky stylu s CSS, jako je tento:

<style>
/* make the slider track red */
input::-webkit-slider-runnable-track {
  background: red;
}
</style>

<input type="range">

Ještě jednou pseudo je nestandardní atribut. Chronologicky, prohlížeče nejprve začaly experimentovat s vnitřními strukturami DOM, aby implementovaly ovládací prvky, a pak, po čase, byl stínový DOM standardizován, aby nám, vývojářům, umožnil udělat podobnou věc.

Dále budeme používat moderní stínový standard DOM, na který se vztahuje specifikace DOM a další související specifikace.

Stínový strom

Element DOM může mít dva typy podstromů DOM:

  1. Světlý strom – běžný podstrom DOM vytvořený z potomků HTML. Všechny podstromy, které jsme viděli v předchozích kapitolách, byly „světlé“.
  2. Stínový strom – skrytý podstrom DOM, který se neodráží v HTML, skrytý před zvědavýma očima.

Pokud má prvek obojí, prohlížeč vykreslí pouze stínový strom. Můžeme ale také nastavit jakousi kompozici mezi stíny a světlými stromy. Podrobnosti uvidíme později v kapitole Stínové DOM sloty, kompozice.

Strom stínů lze v uživatelských prvcích použít ke skrytí vnitřních částí komponent a použití místních stylů komponent.

Například toto <show-hello> prvek skryje svůj vnitřní DOM ve stromě stínů:

<script>
customElements.define('show-hello', class extends HTMLElement {
  connectedCallback() {
    const shadow = this.attachShadow({mode: 'open'});
    shadow.innerHTML = `<p>
      Hello, ${this.getAttribute('name')}
    </p>`;
  }
});
</script>

<show-hello name="John"></show-hello>

Takto vypadá výsledný DOM ve vývojářských nástrojích Chrome, veškerý obsah je pod „#shadow-root“:

Nejprve volání na elem.attachShadow({mode: …}) vytvoří strom stínů.

Existují dvě omezení:

  1. Pro každý prvek můžeme vytvořit pouze jeden kořen stínu.
  2. elem musí být buď vlastní prvek, nebo jeden z:„article“, „aside“, „blockquote“, „body“, „div“, „footer“, „h1…h6“, „header“, „main“ „nav“ "", "p", "sekce" nebo "rozpětí". Další prvky, například <img> , nemůže hostit stínový strom.

mode volba nastavuje úroveň zapouzdření. Musí mít kteroukoli ze dvou hodnot:

  • "open" – kořenový adresář stínů je dostupný jako elem.shadowRoot .

    Jakýkoli kód má přístup ke stromu stínů elem .

  • "closed"elem.shadowRoot je vždy null .

    Ke stínovému DOM můžeme přistupovat pouze pomocí odkazu vráceného attachShadow (a pravděpodobně skrytý uvnitř třídy). Stínové stromy nativní v prohlížeči, jako je <input type="range"> , jsou uzavřeny. Neexistuje způsob, jak se k nim dostat.

Stínový kořen vrácený attachShadow , je jako prvek:můžeme použít innerHTML nebo metody DOM, například append , k naplnění.

Prvek s kořenem stínu se nazývá „hostitel stínového stromu“ a je dostupný jako kořen stínu host vlastnost:

// assuming {mode: "open"}, otherwise elem.shadowRoot is null
alert(elem.shadowRoot.host === elem); // true

Zapouzdření

Shadow DOM je silně oddělen od hlavního dokumentu:

  1. Stínové prvky DOM nejsou viditelné pro querySelector ze světelného DOM. Zejména prvky Shadow DOM mohou mít ID, která jsou v rozporu s těmi ve světlém DOM. Musí být jedinečné pouze v rámci stromu stínů.
  2. Shadow DOM má vlastní šablony stylů. Pravidla stylu z vnějšího modelu DOM se nepoužijí.

Například:

<style>
  /* document style won't apply to the shadow tree inside #elem (1) */
  p { color: red; }
</style>

<div id="elem"></div>

<script>
  elem.attachShadow({mode: 'open'});
    // shadow tree has its own style (2)
  elem.shadowRoot.innerHTML = `
    <style> p { font-weight: bold; } </style>
    <p>Hello, John!</p>
  `;

  // <p> is only visible from queries inside the shadow tree (3)
  alert(document.querySelectorAll('p').length); // 0
  alert(elem.shadowRoot.querySelectorAll('p').length); // 1
</script>
  1. Styl z dokumentu nemá vliv na strom stínů.
  2. …Ale styl zevnitř funguje.
  3. Chceme-li získat prvky ve stínovém stromu, musíme se dotazovat zevnitř stromu.

Odkazy

  • DOM:https://dom.spec.whatwg.org/#shadow-trees
  • Kompatibilita:https://caniuse.com/#feat=shadowdomv1
  • Shadow DOM je zmíněn v mnoha dalších specifikacích, např. Analýza DOM určuje, že kořenový adresář stínů má innerHTML .

Shrnutí

Shadow DOM je způsob, jak vytvořit lokální DOM komponentu.

  1. shadowRoot = elem.attachShadow({mode: open|closed}) – vytvoří stínový DOM pro elem . Pokud mode="open" , pak je přístupný jako elem.shadowRoot vlastnictví.
  2. Můžeme naplnit shadowRoot pomocí innerHTML nebo jiné metody DOM.

Stínové prvky DOM:

  • Mají svůj vlastní prostor pro ID,
  • Neviditelné pro selektory JavaScriptu z hlavního dokumentu, jako je querySelector ,
  • Používejte styly pouze ze stromu stínů, nikoli z hlavního dokumentu.

Stínový DOM, pokud existuje, je vykreslován prohlížečem namísto tzv. „light DOM“ (běžné děti). V kapitole Shadow DOM sloty, kompozice uvidíme, jak je skládat.