DOM nám umožňuje dělat cokoli s prvky a jejich obsahem, ale nejprve se musíme dostat k odpovídajícímu objektu DOM.
Všechny operace na DOM začínají document
objekt. To je hlavní „vstupní bod“ do DOM. Z něj můžeme přistupovat k libovolnému uzlu.
Zde je obrázek odkazů, které umožňují cestování mezi uzly DOM:
Pojďme si je probrat podrobněji.
Nahoře:documentElement a tělo
Nejvyšší uzly stromu jsou dostupné přímo jako document
vlastnosti:
<html>
=document.documentElement
- Nejvyšší uzel dokumentu je
document.documentElement
. To je uzel DOM<html>
tag. <body>
=document.body
- Další široce používaný uzel DOM je
<body>
prvek –document.body
. <head>
=document.head
<head>
tag je dostupný jakodocument.head
.
document.body
může být null
Skript nemůže přistupovat k prvku, který v okamžiku spuštění neexistuje.
Zejména pokud je skript uvnitř <head>
a poté document.body
není k dispozici, protože jej prohlížeč ještě nepřečetl.
Takže v příkladu níže první alert
ukazuje null
:
<html>
<head>
<script>
alert( "From HEAD: " + document.body ); // null, there's no <body> yet
</script>
</head>
<body>
<script>
alert( "From BODY: " + document.body ); // HTMLBodyElement, now it exists
</script>
</body>
</html>
Ve světě DOM null
znamená „neexistuje“
V DOM, null
hodnota znamená „neexistuje“ nebo „není takový uzel“.
Děti:childNodes, firstChild, lastChild
Od této chvíle budeme používat dva termíny:
- Podřízené uzly (nebo děti) – prvky, které jsou přímými dětmi. Jinými slovy, jsou vnořeny přesně do daného. Například
<head>
a<body>
jsou potomky<html>
prvek. - Potomci – všechny prvky, které jsou vnořeny do daného, včetně dětí, jejich dětí a tak dále.
Například zde <body>
má potomky <div>
a <ul>
(a několik prázdných textových uzlů):
<html>
<body>
<div>Begin</div>
<ul>
<li>
<b>Information</b>
</li>
</ul>
</body>
</html>
…A potomci <body>
nejsou pouze přímé potomky <div>
, <ul>
ale také hlouběji vnořené prvky, jako je <li>
(podřízený prvek <ul>
) a <b>
(podřízený prvek <li>
) – celý podstrom.
Číslo childNodes
kolekce uvádí všechny podřízené uzly, včetně textových uzlů.
Níže uvedený příklad ukazuje potomky document.body
:
<html>
<body>
<div>Begin</div>
<ul>
<li>Information</li>
</ul>
<div>End</div>
<script>
for (let i = 0; i < document.body.childNodes.length; i++) {
alert( document.body.childNodes[i] ); // Text, DIV, Text, UL, ..., SCRIPT
}
</script>
...more stuff...
</body>
</html>
Zde si všimněte zajímavého detailu. Pokud spustíme výše uvedený příklad, posledním zobrazeným prvkem je <script>
. Dokument ve skutečnosti obsahuje více věcí níže, ale v okamžiku spuštění skriptu jej prohlížeč ještě nečetl, takže jej skript nevidí.
Vlastnosti firstChild
a lastChild
umožnit rychlý přístup k prvním a posledním dětem.
Jsou to jen zkratky. Pokud existují podřízené uzly, platí vždy následující:
elem.childNodes[0] === elem.firstChild
elem.childNodes[elem.childNodes.length - 1] === elem.lastChild
K dispozici je také speciální funkce elem.hasChildNodes()
zkontrolovat, zda existují nějaké podřízené uzly.
Sbírky DOM
Jak vidíme, childNodes
vypadá jako pole. Ale ve skutečnosti to není pole, ale spíše kolekce – speciální iterovatelný objekt podobný poli.
Má to dva důležité důsledky:
- Můžeme použít
for..of
iterovat to:
for (let node of document.body.childNodes) {
alert(node); // shows all nodes from the collection
}
Je to proto, že je iterovatelný (poskytuje Symbol.iterator
majetku, podle potřeby).
- Metody pole nebudou fungovat, protože to není pole:
alert(document.body.childNodes.filter); // undefined (there's no filter method!)
První věc je pěkná. Druhý je tolerovatelný, protože můžeme použít Array.from
k vytvoření „skutečného“ pole z kolekce, pokud chceme metody pole:
alert( Array.from(document.body.childNodes).filter ); // function
Kolekce DOM jsou pouze pro čtení Kolekce DOM a ještě více – vše navigační vlastnosti uvedené v této kapitole jsou pouze pro čtení.
Nemůžeme nahradit dítě něčím jiným přiřazením childNodes[i] = ...
.
Změna DOM vyžaduje jiné metody. Uvidíme je v další kapitole.
Sbírky DOM jsou aktivníTéměř všechny kolekce DOM s malými výjimkami jsou živé . Jinými slovy, odrážejí aktuální stav DOM.
Pokud ponecháme odkaz na elem.childNodes
a přidat/odebrat uzly do DOM, pak se automaticky objeví v kolekci.
for..in
procházet sbírkami
Kolekce lze iterovat pomocí for..of
. Někdy se lidé snaží použít for..in
za to.
Prosím, ne. for..in
smyčka iteruje přes všechny vyčíslitelné vlastnosti. A kolekce mají některé „extra“ zřídka používané vlastnosti, které obvykle nechceme získat:
<body>
<script>
// shows 0, 1, length, item, values and more.
for (let prop in document.body.childNodes) alert(prop);
</script>
</body>
Sourozenci a rodič
Sourozenci jsou uzly, které jsou potomky stejného rodiče.
Například zde <head>
a <body>
jsou sourozenci:
<html>
<head>...</head><body>...</body>
</html>
<body>
se říká, že je „dalším“ nebo „pravým“ sourozencem<head>
,<head>
je považován za „předchozího“ nebo „levého“ sourozence<body>
.
Další sourozenec je v nextSibling
vlastnost a předchozí – v previousSibling
.
Rodič je dostupný jako parentNode
.
Například:
// parent of <body> is <html>
alert( document.body.parentNode === document.documentElement ); // true
// after <head> goes <body>
alert( document.head.nextSibling ); // HTMLBodyElement
// before <body> goes <head>
alert( document.body.previousSibling ); // HTMLHeadElement
Navigace pouze pro prvky
Výše uvedené vlastnosti navigace odkazují na vše uzly. Například v childNodes
můžeme vidět textové uzly, uzly prvků a dokonce i uzly komentářů, pokud existují.
Ale pro mnoho úkolů nechceme uzly textu nebo komentářů. Chceme manipulovat s uzly prvků, které představují značky a tvoří strukturu stránky.
Pojďme se tedy podívat na další navigační odkazy, které přebírají pouze uzly prvků v úvahu:
Odkazy jsou podobné těm, které jsou uvedeny výše, pouze s Element
slovo uvnitř:
children
– pouze ty potomky, které jsou uzly prvků.firstElementChild
,lastElementChild
– děti prvního a posledního prvku.previousElementSibling
,nextElementSibling
– sousední prvky.parentElement
– nadřazený prvek.
parentElement
? Může být rodič ne prvek?
parentElement
vlastnost vrací „element“ rodiče, zatímco parentNode
vrátí rodič „libovolný uzel“. Tyto vlastnosti jsou obvykle stejné:obě získají rodiče.
S jedinou výjimkou document.documentElement
:
alert( document.documentElement.parentNode ); // document
alert( document.documentElement.parentElement ); // null
Důvodem je kořenový uzel document.documentElement
(<html>
) má document
jako její rodič. Ale document
není uzel prvku, takže parentNode
vrátí jej a parentElement
ne.
Tento detail může být užitečný, když chceme přejít nahoru od libovolného prvku elem
na <html>
, ale ne na document
:
while(elem = elem.parentElement) { // go up till <html>
alert( elem );
}
Upravme jeden z výše uvedených příkladů:nahraďte childNodes
s children
. Nyní zobrazuje pouze prvky:
<html>
<body>
<div>Begin</div>
<ul>
<li>Information</li>
</ul>
<div>End</div>
<script>
for (let elem of document.body.children) {
alert(elem); // DIV, UL, DIV, SCRIPT
}
</script>
...
</body>
</html>
Další odkazy:tabulky
Dosud jsme popsali základní vlastnosti navigace.
Některé typy prvků DOM mohou pro pohodlí poskytovat další vlastnosti specifické pro jejich typ.
Tabulky jsou toho skvělým příkladem a představují obzvláště důležitý případ:
<table>
prvek podporuje (kromě výše uvedeného) tyto vlastnosti:
table.rows
– kolekce<tr>
prvky tabulky.table.caption/tHead/tFoot
– odkazy na prvky<caption>
,<thead>
,<tfoot>
.table.tBodies
– kolekce<tbody>
prvků (podle standardu může být mnoho, ale vždy bude alespoň jeden – i když není ve zdrojovém HTML, prohlížeč ho vloží do DOM).
<thead>
, <tfoot>
, <tbody>
prvky poskytují rows
vlastnost:
tbody.rows
– kolekce<tr>
uvnitř.
<tr>
:
tr.cells
– kolekce<td>
a<th>
buňky uvnitř daného<tr>
.tr.sectionRowIndex
– pozice (index) daného<tr>
uvnitř přiloženého<thead>/<tbody>/<tfoot>
.tr.rowIndex
– číslo<tr>
v tabulce jako celku (včetně všech řádků tabulky).
<td>
a <th>
:
td.cellIndex
– číslo buňky uvnitř<tr>
.
Příklad použití:
<table id="table">
<tr>
<td>one</td><td>two</td>
</tr>
<tr>
<td>three</td><td>four</td>
</tr>
</table>
<script>
// get td with "two" (first row, second column)
let td = table.rows[0].cells[1];
td.style.backgroundColor = "red"; // highlight it
</script>
Specifikace:tabulková data.
Existují také další navigační vlastnosti pro formuláře HTML. Podíváme se na ně později, až začneme pracovat s formuláři.
Shrnutí
Vzhledem k uzlu DOM můžeme přejít k jeho bezprostředním sousedům pomocí navigačních vlastností.
Jsou dvě hlavní sady:
- Pro všechny uzly:
parentNode
,childNodes
,firstChild
,lastChild
,previousSibling
,nextSibling
. - Pouze pro uzly prvků:
parentElement
,children
,firstElementChild
,lastElementChild
,previousElementSibling
,nextElementSibling
.
Některé typy prvků DOM, např. tabulky, poskytují další vlastnosti a kolekce pro přístup k jejich obsahu.