Vlastnosti uzlu:typ, značka a obsah

Pojďme se na uzly DOM podívat podrobněji.

V této kapitole se podíváme více na to, co to je, a naučíme se jejich nejpoužívanější vlastnosti.

Třídy uzlů DOM

Různé uzly DOM mohou mít různé vlastnosti. Například uzel prvku odpovídající tagu <a> má vlastnosti související s odkazem a tu, která odpovídá <input> má vlastnosti související se vstupem a tak dále. Textové uzly nejsou stejné jako uzly prvků. Ale mezi všemi jsou také společné vlastnosti a metody, protože všechny třídy uzlů DOM tvoří jedinou hierarchii.

Každý uzel DOM patří do odpovídající vestavěné třídy.

Kořenem hierarchie je EventTarget, který zdědí Node a ostatní uzly DOM z něj dědí.

Zde je obrázek, vysvětlivky, které je třeba následovat:

Třídy jsou:

  • EventTarget – je kořenová „abstraktní“ třída pro všechno.

    Objekty této třídy nejsou nikdy vytvořeny. Slouží jako základ, takže všechny uzly DOM podporují takzvané „události“, prostudujeme je později.

  • Node – je také „abstraktní“ třída, která slouží jako základ pro uzly DOM.

    Poskytuje základní funkcionalitu stromu:parentNode , nextSibling , childNodes a tak dále (jsou to getry). Objekty Node třída se nikdy nevytvoří. Ale existují i ​​jiné třídy, které z něj dědí (a tak dědí Node funkčnost).

  • Dokument, z historických důvodů často zděděný HTMLDocument (ačkoli to nejnovější specifikace nenařizuje) – je dokument jako celek.

    document globální objekt patří přesně do této třídy. Slouží jako vstupní bod do DOM.

  • CharacterData – „abstraktní“ třída, kterou zdědí:

    • Text – třída odpovídající textu uvnitř prvků, např. Hello v <p>Hello</p> .
    • Komentář – třída pro komentáře. Nejsou zobrazeny, ale každý komentář se stává členem DOM.
  • Element – ​​je základní třída pro prvky DOM.

    Poskytuje navigaci na úrovni prvků, jako je nextElementSibling , children a vyhledávací metody jako getElementsByTagName , querySelector .

    Prohlížeč podporuje nejen HTML, ale také XML a SVG. Takže Element class slouží jako základ pro specifičtější třídy:SVGElement , XMLElement (zde je nepotřebujeme) a HTMLElement .

  • Konečně HTMLElement je základní třída pro všechny HTML elementy. Většinu času s tím budeme pracovat.

    Dědí se konkrétními prvky HTML:

    • HTMLInputElement – ​​třída pro <input> prvky,
    • HTMLBodyElement – ​​třída pro <body> prvky,
    • HTMLAnchorElement – ​​třída pro <a> prvky,
    • …a tak dále.

Existuje mnoho dalších značek s vlastními třídami, které mohou mít specifické vlastnosti a metody, zatímco některé prvky, jako je <span> , <section> , <article> nemají žádné specifické vlastnosti, takže jsou instancemi HTMLElement třída.

Úplná sada vlastností a metod daného uzlu je tedy výsledkem řetězce dědičnosti.

Vezměme si například objekt DOM pro <input> živel. Patří do třídy HTMLInputElement.

Získá vlastnosti a metody jako superpozici (uvedené v pořadí dědičnosti):

  • HTMLInputElement – tato třída poskytuje vlastnosti specifické pro vstup,
  • HTMLElement – poskytuje běžné metody HTML elementů (a getters/setters),
  • Element – poskytuje metody obecných prvků,
  • Node – poskytuje běžné vlastnosti uzlu DOM,
  • EventTarget – poskytuje podporu akcím (které mají být pokryty),
  • …a nakonec dědí z Object , takže metody „prostého objektu“ jako hasOwnProperty jsou také k dispozici.

Abychom viděli název třídy uzlu DOM, můžeme si připomenout, že objekt má obvykle constructor vlastnictví. Odkazuje na konstruktor třídy a constructor.name je jeho jméno:

alert( document.body.constructor.name ); // HTMLBodyElement

…Nebo můžeme jen toString to:

alert( document.body ); // [object HTMLBodyElement]

Můžeme také použít instanceof pro kontrolu dědictví:

alert( document.body instanceof HTMLBodyElement ); // true
alert( document.body instanceof HTMLElement ); // true
alert( document.body instanceof Element ); // true
alert( document.body instanceof Node ); // true
alert( document.body instanceof EventTarget ); // true

Jak vidíme, uzly DOM jsou běžné objekty JavaScriptu. Pro dědění používají třídy založené na prototypech.

To lze také snadno zjistit, když prvek vypíšete s console.dir(elem) v prohlížeči. V konzole můžete vidět HTMLElement.prototype , Element.prototype a tak dále.

console.dir(elem) oproti console.log(elem)

Většina prohlížečů podporuje ve svých vývojářských nástrojích dva příkazy:console.log a console.dir . Vydávají své argumenty do konzole. U objektů JavaScriptu tyto příkazy obvykle dělají totéž.

Ale pro prvky DOM jsou jiné:

  • console.log(elem) zobrazuje strom DOM prvku.
  • console.dir(elem) zobrazuje prvek jako objekt DOM, je dobré prozkoumat jeho vlastnosti.

Zkuste to na document.body .

IDL ve spec

Ve specifikaci nejsou třídy DOM popsány pomocí JavaScriptu, ale speciálního jazyka pro popis rozhraní (IDL), který je obvykle snadno srozumitelný.

V IDL jsou všechny vlastnosti doplněny o jejich typy. Například DOMString , boolean a tak dále.

Zde je úryvek z něj s komentáři:

// Define HTMLInputElement
// The colon ":" means that HTMLInputElement inherits from HTMLElement
interface HTMLInputElement: HTMLElement {
 // here go properties and methods of <input> elements

 // "DOMString" means that the value of a property is a string
 attribute DOMString accept;
 attribute DOMString alt;
 attribute DOMString autocomplete;
 attribute DOMString value;

 // boolean value property (true/false)
 attribute boolean autofocus;
 ...
 // now the method: "void" means that the method returns no value
 void select();
 ...
}

Vlastnost „nodeType“

nodeType property poskytuje ještě jeden „staromódní“ způsob, jak získat „typ“ uzlu DOM.

Má číselnou hodnotu:

  • elem.nodeType == 1 pro uzly prvků,
  • elem.nodeType == 3 pro textové uzly,
  • elem.nodeType == 9 pro objekt dokumentu,
  • ve specifikaci je několik dalších hodnot.

Například:

<body>
 <script>
 let elem = document.body;

 // let's examine: what type of node is in elem?
 alert(elem.nodeType); // 1 => element

 // and its first child is...
 alert(elem.firstChild.nodeType); // 3 => text

 // for the document object, the type is 9
 alert( document.nodeType ); // 9
 </script>
</body>

V moderních skriptech můžeme použít instanceof a další testy založené na třídách, abyste viděli typ uzlu, ale někdy nodeType může být jednodušší. Můžeme číst pouze nodeType , neměnit.

Značka:nodeName a tagName

Daný uzel DOM můžeme přečíst název jeho značky z nodeName nebo tagName vlastnosti:

Například:

alert( document.body.nodeName ); // BODY
alert( document.body.tagName ); // BODY

Je nějaký rozdíl mezi tagName? a nodeName ?

Jistě, rozdíl se odráží v jejich jménech, ale je skutečně trochu jemný.

  • tagName vlastnost existuje pouze pro Element uzly.
  • nodeName je definován pro libovolný Node :
    • pro prvky to znamená totéž jako tagName .
    • pro ostatní typy uzlů (text, komentář atd.) má řetězec s typem uzlu.

Jinými slovy, tagName je podporováno pouze uzly prvků (protože pochází z Element class), zatímco nodeName může říci něco o jiných typech uzlů.

Porovnejme například tagName a nodeName pro document a uzel komentáře:

<body><!-- comment -->

 <script>
 // for comment
 alert( document.body.firstChild.tagName ); // undefined (not an element)
 alert( document.body.firstChild.nodeName ); // #comment

 // for document
 alert( document.tagName ); // undefined (not an element)
 alert( document.nodeName ); // #document
 </script>
</body>

Pokud se zabýváme pouze prvky, pak můžeme použít oba tagName a nodeName – není v tom žádný rozdíl.

Název značky je vždy velkými písmeny kromě režimu XML

Prohlížeč má dva režimy zpracování dokumentů:HTML a XML. Obvykle se pro webové stránky používá režim HTML. Režim XML je povolen, když prohlížeč obdrží dokument XML se záhlavím:Content-Type: application/xml+xhtml .

V režimu HTML tagName/nodeName je vždy velká:je to BODY buď pro <body> nebo <BoDy> .

V režimu XML je velikost písmen zachována „tak jak je“. V současné době se režim XML používá zřídka.

vnitřní HTML:obsah

Vlastnost innerHTML umožňuje dostat HTML dovnitř prvku jako řetězec.

Můžeme ho také upravit. Je to tedy jeden z nejúčinnějších způsobů, jak změnit stránku.

Příklad ukazuje obsah document.body a poté jej zcela nahradí:

<body>
 <p>A paragraph</p>
 <div>A div</div>

 <script>
 alert( document.body.innerHTML ); // read the current contents
 document.body.innerHTML = 'The new BODY!'; // replace it
 </script>

</body>

Můžeme zkusit vložit neplatné HTML, prohlížeč naše chyby opraví:

<body>

 <script>
 document.body.innerHTML = '<b>test'; // forgot to close the tag
 alert( document.body.innerHTML ); // <b>test</b> (fixed)
 </script>

</body>
Skripty se nespouštějí

Pokud innerHTML vloží <script> tag do dokumentu – stane se součástí HTML, ale nespustí se.

Pozor:„innerHTML+=“ provede úplné přepsání

HTML můžeme k prvku připojit pomocí elem.innerHTML+="more html" .

Takhle:

chatDiv.innerHTML += "<div>Hello<img src='smile.gif'/> !</div>";
chatDiv.innerHTML += "How goes?";

Měli bychom to ale dělat velmi opatrně, protože to, co se děje, není přidání, ale úplné přepsání.

Technicky tyto dva řádky dělají totéž:

elem.innerHTML += "...";
// is a shorter way to write:
elem.innerHTML = elem.innerHTML + "..."

Jinými slovy innerHTML+= dělá toto:

  1. Starý obsah je odstraněn.
  2. Nový innerHTML místo toho se píše (zřetězení starého a nového).

Protože je obsah „vynulován“ a přepsán od začátku, všechny obrázky a další zdroje budou znovu načteny .

V chatDiv příklad nad řádkem chatDiv.innerHTML+="How goes?" znovu vytvoří obsah HTML a znovu načte smile.gif (doufám, že je v mezipaměti). Pokud chatDiv obsahuje mnoho dalšího textu a obrázků, pak je opětovné načtení jasně viditelné.

Existují i ​​další vedlejší účinky. Pokud byl například existující text vybrán pomocí myši, většina prohlížečů výběr odstraní po přepsání innerHTML . A pokud tam byl <input> s textem zadaným návštěvníkem, pak bude text odstraněn. A tak dále.

Naštěstí existují jiné způsoby, jak přidat HTML kromě innerHTML a brzy je prostudujeme.

outerHTML:úplné HTML prvku

outerHTML vlastnost obsahuje úplné HTML prvku. To je jako innerHTML plus samotný prvek.

Zde je příklad:

<div id="elem">Hello <b>World</b></div>

<script>
 alert(elem.outerHTML); // <div id="elem">Hello <b>World</b></div>
</script>

Pozor:na rozdíl od innerHTML , zápis na outerHTML nezmění prvek. Místo toho jej nahradí v DOM.

Jo, zní to divně a divně to je, proto o tom zde uvádíme samostatnou poznámku. Podívejte se.

Zvažte příklad:

<div>Hello, world!</div>

<script>
 let div = document.querySelector('div');

 // replace div.outerHTML with <p>...</p>
 div.outerHTML = '<p>A new element</p>'; // (*)

 // Wow! 'div' is still the same!
 alert(div.outerHTML); // <div>Hello, world!</div> (**)
</script>

Vypadá to opravdu divně, že?

V řádku (*) nahradili jsme div s <p>A new element</p> . Ve vnějším dokumentu (DOM) můžeme vidět nový obsah místo <div> . Ale jak vidíme na řádku (**) , hodnota starého div proměnná se nezměnila!

outerHTML přiřazení nemění prvek DOM (objekt, na který odkazuje v tomto případě proměnná ‚div‘), ale odstraňuje jej z modelu DOM a vkládá na jeho místo nový kód HTML.

Co se tedy stalo v div.outerHTML=... je:

  • div byl z dokumentu odstraněn.
  • Další kus HTML <p>A new element</p> byl vložen na jeho místo.
  • div má stále svou starou hodnotu. Nový kód HTML nebyl uložen do žádné proměnné.

Zde je tak snadné udělat chybu:upravit div.outerHTML a poté pokračujte v práci s div jako by v něm byl nový obsah. Ale není. Taková věc je správná pro innerHTML , ale ne pro outerHTML .

Můžeme zapisovat do elem.outerHTML , ale měli byste mít na paměti, že to nemění prvek, do kterého píšeme („elem“). Místo toho umístí nový HTML na své místo. Odkazy na nové prvky můžeme získat dotazem na DOM.

nodeValue/data:obsah textového uzlu

innerHTML vlastnost je platná pouze pro uzly prvků.

Jiné typy uzlů, jako jsou textové uzly, mají svůj protějšek:nodeValue a data vlastnosti. Tyto dva jsou pro praktické použití téměř stejné, existují pouze drobné rozdíly ve specifikaci. Použijeme tedy data , protože je kratší.

Příklad čtení obsahu textového uzlu a komentáře:

<body>
 Hello
 <!-- Comment -->
 <script>
 let text = document.body.firstChild;
 alert(text.data); // Hello

 let comment = text.nextSibling;
 alert(comment.data); // Comment
 </script>
</body>

U textových uzlů si můžeme představit důvod, proč je číst nebo upravovat, ale proč komentáře?

Někdy do nich vývojáři vkládají informace nebo pokyny šablony do HTML, například takto:

<!-- if isAdmin -->
 <div>Welcome, Admin!</div>
<!-- /if -->

…Pak to JavaScript může číst od data vložené instrukce pro vlastnosti a procesy.

textContent:čistý text

textContent poskytuje přístup k textu uvnitř prvku:pouze text, minus vše <tags> .

Například:

<div id="news">
 <h1>Headline!</h1>
 <p>Martians attack people!</p>
</div>

<script>
 // Headline! Martians attack people!
 alert(news.textContent);
</script>

Jak vidíme, vrací se pouze text, jako by vše <tags> byly vystřiženy, ale text v nich zůstal.

V praxi je čtení takového textu málokdy potřeba.

Zápis do textContent je mnohem užitečnější, protože umožňuje psát text „bezpečným způsobem“.

Řekněme, že máme libovolný řetězec, například zadaný uživatelem, a chceme jej zobrazit.

  • S innerHTML vložíme jej „jako HTML“ se všemi značkami HTML.
  • S textContent vložíme jej „jako text“, se všemi symboly se zachází doslova.

Porovnejte oba:

<div id="elem1"></div>
<div id="elem2"></div>

<script>
 let name = prompt("What's your name?", "<b>Winnie-the-Pooh!</b>");

 elem1.innerHTML = name;
 elem2.textContent = name;
</script>
  1. První <div> dostane název „jako HTML“:všechny značky se stanou značkami, takže vidíme název tučně.
  2. Druhý <div> dostane jméno „jako text“, takže doslova vidíme <b>Winnie-the-Pooh!</b> .

Ve většině případů očekáváme text od uživatele a chceme s ním zacházet jako s textem. Na našem webu nechceme neočekávané HTML. Přiřazení do textContent dělá přesně to.

Vlastnost „skrytá“

Atribut „hidden“ a vlastnost DOM určují, zda je prvek viditelný nebo ne.

Můžeme jej použít v HTML nebo jej přiřadit pomocí JavaScriptu, takto:

<div>Both divs below are hidden</div>

<div hidden>With the attribute "hidden"</div>

<div id="elem">JavaScript assigned the property "hidden"</div>

<script>
 elem.hidden = true;
</script>

Technicky vzato, hidden funguje stejně jako style="display:none" . Ale je to kratší na psaní.

Zde je blikající prvek:

<div id="elem">A blinking element</div>

<script>
 setInterval(() => elem.hidden = !elem.hidden, 1000);
</script>

Další vlastnosti

Prvky DOM mají také další vlastnosti, zejména ty, které závisí na třídě:

  • value – hodnota pro <input> , <select> a <textarea> (HTMLInputElement , HTMLSelectElement …).
  • href – „href“ pro <a href="..."> (HTMLAnchorElement ).
  • id – hodnota atributu „id“ pro všechny prvky (HTMLElement ).
  • …a mnohem více…

Například:

<input type="text" id="elem" value="value">

<script>
 alert(elem.type); // "text"
 alert(elem.id); // "elem"
 alert(elem.value); // value
</script>

Většina standardních atributů HTML má odpovídající vlastnost DOM a můžeme k ní takto přistupovat.

Pokud chceme znát úplný seznam podporovaných vlastností pro danou třídu, najdeme je ve specifikaci. Například HTMLInputElement je zdokumentován na https://html.spec.whatwg.org/#htmlinputelement.

Nebo pokud je chceme získat rychle nebo máme zájem o konkrétní specifikaci prohlížeče – vždy můžeme prvek vypsat pomocí console.dir(elem) a přečtěte si vlastnosti. Nebo prozkoumejte „Vlastnosti DOM“ na kartě Prvky nástrojů pro vývojáře prohlížeče.

Shrnutí

Každý uzel DOM patří do určité třídy. Třídy tvoří hierarchii. Úplná sada vlastností a metod pochází z dědičnosti.

Hlavní vlastnosti uzlu DOM jsou:

nodeType
Můžeme jej použít ke zjištění, zda je uzel textový nebo uzel prvku. Má číselnou hodnotu:1 pro prvky 3 pro textové uzly a několik dalších pro jiné typy uzlů. Pouze pro čtení.
nodeName/tagName
U prvků název značky (velká písmena, pokud není v režimu XML). Pro neprvkové uzly nodeName popisuje, co to je. Pouze pro čtení.
innerHTML
Obsah HTML prvku. Lze upravit.
outerHTML
Úplný kód HTML prvku. Operace zápisu do elem.outerHTML nedotýká elem sám. Místo toho bude nahrazen novým HTML ve vnějším kontextu.
nodeValue/data
Obsah neprvkového uzlu (text, komentář). Tyto dva jsou téměř stejné, obvykle používáme data . Lze upravit.
textContent
Text uvnitř prvku:HTML minus vše <tags> . Zápis do něj vloží text do prvku, přičemž všechny speciální znaky a značky budou zpracovány přesně jako text. Může bezpečně vkládat uživatelsky generovaný text a chránit před nechtěným vkládáním HTML.
hidden
Při nastavení na true , dělá to samé jako CSS display:none .

Uzly DOM mají také další vlastnosti v závislosti na jejich třídě. Například <input> prvky (HTMLInputElement ) podporuje value , type , zatímco <a> prvky (HTMLAnchorElement ) podporuje href atd. Většina standardních atributů HTML má odpovídající vlastnost DOM.

Atributy HTML a vlastnosti DOM však nejsou vždy stejné, jak uvidíme v další kapitole.