Lekce 9 - Manipulace s DOM v JavaScriptu

JavaScript Základní konstrukce Manipulace s DOM v JavaScriptu American English version English version

ONEbit hosting Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, Základy práce s DOM a události v JavaScriptu, jsme začali tou nejčastěji používanou metodou DOMu - getElementById() a řekli jsme si něco o událostech. Dnešní JavaScript tutoriál bude ryze teoretický. Ukážeme si, co vše lze provádět v DOMu a v příští lekci vytvoříme již skutečně rozsáhlejší webovou aplikaci, která bude čerpat právě ze znalostí nabytých v této lekci.

Výběr elementů

Než se do manipulace elementů pustíme, musíme si je nějak najít. Metoda getElementById() je sice velmi účelná (a rychlá), ale není vždy ideální. Někdy je potřeba vybrat více elementů a někdy je třeba vybrat elementy bez id. Není totiž podmínkou, že budeme vybírat z dokumentu, ke kterému máme přístup a přítomnost id si zajistíme sami.

Výběr na základě třídy

Tento výběr zajišťuje metoda getElementsByClassName(). Při jejím psaní si dávejte pozor, že elements je množné číslo a každé první písmeno slova (kromě prvního slova) je velké. Pokud to spletete, obdržíte chybu (asi ji však neuvidíte, chyby zobrazují pouze starší verze IE). Metoda vrací pole všech elementů, které mají danou třídu. Pokud takovou třídu nemá žádný element, vrátí metoda prázdné pole (zcela přesně, vrátí prázdný HTMLCollection, což je hloupější pole určené k uchovávání HTML elementů).

document.getElementsByClassName("class");

Výběr na základě tagu

Každý element má tag, což je jeho značka (typ). Metoda getElementsByTagName() vrací všechny elementy, které mají danou značku. Tímto způsobem můžeme například vybrat všechny textové elementy. Pokud žádný element takový tag nemá, vrátí prázdnou HTMLCollection.

document.getElementsByTagName("tag");

Existují ještě metody pro výběr na základě tagu a jeho jmenného prostoru (getElementsByTagNameNS()). Ty ocení zejména znalci XML a vyhledávání na základě jména (getElementsByName()), což se používá pro vyhledávání prvků ve formulářích, kde se atribut name používá. Obě metody v případě, kdy nic nesplňuje zadané podmínky, vrátí rovněž prázdnou HTMLCollection.

document.getElementsByName("name");
document.getElementsByTagNameNS("tag", "NS");

Výběr podle CSS selektoru

V HTML dokumentu můžeme vyhledávat ještě mnohem pohodlněji a to pomocí CSS selektorů, jak jsme zvyklí z webdesignu. Existují dvě metody, které mám toto umožní. Metoda querySelector() vrátí první element, který tento selektor splňuje a metoda querySelectorAll() vrátí pole všech elementů, pro které daný selektor platí. Ukážeme si to rovnou na příkladu.

document.querySelector("input[type=text].hezky#uvodni");

Tento selektor vrátí element <input>, jehož atribut type je nastavený na text, má třídu .hezky a zároveň id #uvodni. Možná jste si všimli, že když vyhledáváme na základě id, stačil by teoreticky selektor pouze takto (id musí být jedinečné).

document.querySelector("#uvodni");

O trochu zajímavější to bude s metodou querySelectorAll(), která v mnohých případech může být jediná možnost jak něco vybrat.

document.querySelectorAll("div[data-countdown]");

Tento selektor vrátí všechny elementy, které mají nastavený atribut data-countdown. Když jsme již schopni vybrat úplně každý element v DOM, můžeme se pustit do jejich editace.

Editace obsahu DOM

innerHTML

Nejprve se podíváme na samotný obsah elementů. Jednou z nejzákladnějších vlastností elementů z DOM je vlastnost innerHTML, která reprezentuje obsah elementu. Na elementu <p>:

<p><span>Hello</span>world</p>

Načtení této vlastnosti

p.innerHTML

vrátí <span>Hello</span>world. Obsah elementu můžeme úplně stejně i měnit. Jen je potřeba pamatovat na to, že se vnitřní HTML tagy zpracují.

innerText

Podobně jako innerHTML funguje i vlastnost innerText. Jediný rozdíl je, že innerText neobsahuje vnořené HTML elementy, ale pouze jejich textový obsah. Použijeme-li stejný obsah jako u příkladu výše, p.innerText vrátí "Hello world". Vlastnost byla dříve nestandardní, ale všechny prohlížeče ji dnes již podporují.

textContent

textContent dělá téměř totéž co innerText. Rozdíl mezi vlastnostmi je, že innerText vrací pouze viditelný text, zatímco textContent vrací i text skrytý přes CSS.

Nyní již víme jak číst/měnit obsah elementů. Nyní se podíváme na jejich atributy.

Editace atributů DOM

Má atribut?

Základní otázkou je zda element hledaný atribut vůbec má. To zjistíme metodou hasAttribute(), která jako parametr bere název atributu a vrací booleanovskou hodnotu. Existuje i metoda hasAttributes() (množné číslo), která vrací, jestli má element vůbec nějaký atribut. Pokud nemá žádný, vrátí false, pokud má alespoň jeden, vrátí true. Tato metoda nebere žádný parametr. Metoda má i variantu se jmenným prostorem a může vracet i Node atributu (jeho uzel ve stromu) volitelně se jmenným prostorem.

p.hasAttribute("data-velikost");

Potomci elementu

Element může a nemusí mít potomky. Jsou to všechny elementy, které jsou v něm vnořené. Jako příklad si uvedeme formulář:

<form>
        <input type="text" />
        <button>Odeslat</button>
</form>

Elementy <input> a <button> jsou potomky elementu <form>.

Výběr potomků

Seznam všech potomků elementu je v jeho vlastnosti, poli childNodes (zcela přesně to opět není pole, ale tentokrát NodeList).

firstChild

Potomci jsou samozřejmě nějak řazeni a to od nejstaršího po nejmladšího co do doby vložení. Jednodušeji řečeno, jsou v takovém pořadí, v jakém je prohlížeč načítal (již víme, že odshora dolů). Vlastnost firstChild obsahuje prvního z nich.

lastChild

Je naopak poslední potomek.

Je třeba dodat, že vlastnosti firstChild a lastChild nemusí nutně obsahovat jen fyzické elementy, ale třeba i HTML komentáře, textové řetězce (typicky má element <p> potomka, což je jeho obsah - text) a spoustu dalších, které nás většinou nezajímají (pokud parsujeme XML, je to jiná, k tomu se dostaneme u AJAXu). Z praktického hlediska tu máme proto ještě firstElementChild a lastElementChild, kteří vynechávají všechny "serepetičky" kolem (dost zákeřné jsou bílé znaky :) ) a vrátí nám pouze HTML elementy.

Tvorba elementů

Metodou createElement(), vytvoříme element. Tag se udává jako textový řetězec v prvním parametru. Metoda vrátí nový element, se kterým můžeme jakkoliv pracovat, ale musíme si pamatovat, že tento element nikde v dokumentu zatím ještě není. Můžeme do něj vytvářet a vkládat další elementy, ale dokud jej někam do dokumentu nevložíme, neuvidíme je. Existuje ještě varianta, která vytvoří element a předá mu jmenný prostor - createElementNS().

let span = document.createElement("span");
let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");

Vkládání a přesouvání elementů

Element vložíme do jiného elementu pomocí metody appendChild(). Metoda nový element vloží za posledního potomka. Pokud metodě předáme element, který již je někde vložený, element přesuneme. Na původním místě se odstraní.

p.appendChild(span);

Vkládání před nějaký element

Čas od času se nám moc nehodí, když nám metoda appendChild() přidá element až za poslední. Existuje metoda insertBefore(), která jako první parametr příjme nový element a jako druhý element, před který se nový element vloží/přesune.

document.body.insertBefore(span, p);

Nahrazování potomků

Potomka elementu můžeme nahradit. Dělá to metoda replaceChild(), která jako první parametr přijímá nového potomka a jako druhý parametr původního potomka.

svg.replaceChild(arc, rect);

Mazání potomků

Potomka elementu můžeme odstranit metodou removeChild(), která jako parametr bere potomka:

p.removeChild(span);

Rodič elementu

Každý element má svého rodiče (element, do kterého náleží). Pouze jediný element ho nemá – kořenový element <html>. Rodiče elementu získáme pomocí vlastnosti parentElement (funguje i parentNode, které vrací i ty většinou nevyužitelné uzly okolo). U elementu <html> vrátí Null. Element HTML se v dokumentech i někdy úplně vynechává, podle specifikace není nutný.

No a jsme na konci. Vyjmenovali jsme si takřka (možná na nějakou s NS jsem zapomněl) všechny metody a vlastnosti, které nám nějakou cestou vrátí jiný element/atribut/ob­sah elementu a ukázali jsme si, jak můžeme měnit obsah a atributy elementu. Abychom si znalosti ukotvili v paměti, tak si v příští lekci, Editor tabulek v JavaScriptu, vše prakticky vyzkoušíme. Konečně si vytvoříme skutečně rozsáhlou aplikaci, kterou si už těžko půjde splést s webovou stránkou. :)


 

 

Článek pro vás napsal Michal Žůrek - misaz
Avatar
Jak se ti líbí článek?
28 hlasů
Autor se věnuje tvorbě aplikací pro počítače, mobilní telefony, mikroprocesory a tvorbě webových stránek a webových aplikací. Nejraději programuje ve Visual Basicu a TypeScript. Ovládá HTML, CSS, JavaScript, TypeScript, C# a Visual Basic.
Aktivity (7)

 

 

Komentáře
Zobrazit starší komentáře (20)

Avatar
Michal Žůrek - misaz:22.11.2016 12:24

chyba může být na spoustě míst, zmáčkni F12 a podívej se jestli v konzoli není nějaký error. Předpokládám, že se snažíš načíst element P když ještě není načtený. Popis najdeš v některém z úvodních dílů včetně odpovědi na otázku, kde je nejlepší mít umístěn element script.

Odpovědět 22.11.2016 12:24
Nesnáším {}, proto se jim vyhýbám.
Avatar
Jirka
Člen
Avatar
Odpovídá na Michal Žůrek - misaz
Jirka:22.11.2016 12:34

Děkuji, jednoznačnou odpověď, kam psát script jsem zatím nedohledal, možná: "Skripty se někdy alternativně vkládají také těsně před </ body>. U větších aplikací bychom si na javascriptové soubory měli ideálně vytvořit nějakou složku, nabízí ze názvy skripty, scripts, js a podobně.", což mi úplně oči neotevřelo.
Script funguje, pokud ho vložím do těla HTML dokument pod text, avšak kód:

var tag = document.getElementsByTagName("p")[0].innerHTML;
document.write(tag);

mi nevrátí dle tutoriálu mi nevrátí text: "<span>Hello</span>wor­ld", ale " Helloworld".

Poslední dotaz je obecně ke getElement(s), v případě, že objektu přidám např. třídu "haha"

var tag = document.getElementsByClassName("haha");
document.write(tag);

tak mi vypíše [object HTMLCollection], je tedy nutné vždy upřesnit(.inner­HTML, .textContent)?

Omlouvám se za možná stupidní dotazy, avšak z článku to není dost zřejmé nebo jsem to nepochopil :-|

Děkuji

Jirka

 
Odpovědět 22.11.2016 12:34
Avatar
Michal Žůrek - misaz:22.11.2016 19:41
var tag = document.getElementsByTagName("p")[0].innerHTML;
document.write(tag);

ve skutečnosti vrátí <span>Hello</span>wor­ld
, akorát jak ho to vloží do dokumentu, tak to prohlížeč začne interpretovat a ty značky tam nejdou vidět.

document.getElementsByClassName("haha");

vrací kolekci elementů. Kolekci elementů nemůžeš takhle vypsat. Pokud se učíš s DOM doporučuji zapomenout že existuje nějaká prokletá metoda document.write a skutečně to udělat přes DOM. ty souvislosti si tam víc uvědomíš.

Odpovědět 22.11.2016 19:41
Nesnáším {}, proto se jim vyhýbám.
Avatar
naja_adamova
Člen
Avatar
naja_adamova:12.6.2017 21:39

Tak nevim, ale to p.innerHTML nefunguje. Leda
document.getE­lementsByTagNa­me("p")
alert(p[0].in­nerHTML)
pak zobrazi obsah elementu

A taky jsem nasla
http://www.ivt.mzf.cz/…javascriptu/
se stejnym obsahem

Ze by stejny autor?

 
Odpovědět 12.6.2017 21:39
Avatar
naja_adamova
Člen
Avatar
naja_adamova:12.6.2017 21:42

Oprava, skoda, ze uz to nejde editovat
var p=document.ge­tElementsByTag­Name("p")
//v p jsou ulozeny vsechny odstavce indexovany od 0
alert(p[0].in­nerHTML)
//obsah prvniho

 
Odpovědět 12.6.2017 21:42
Avatar
Odpovídá na naja_adamova
Michal Žůrek - misaz:12.6.2017 21:51

ahoj, ukázka kódu předpokládá, že v proměnné p je již nějaký elment načtený libovolnou z výběrových metod (viz. výše v článku).

Děkuji také za upozornění na plagiát. Jsem originálním autorem článku. Gymnázium (nebo někdo kdo se tak vydává) je "uwarezil" a budu to řešit.

Odpovědět 12.6.2017 21:51
Nesnáším {}, proto se jim vyhýbám.
Avatar
naja_adamova
Člen
Avatar
naja_adamova:12.6.2017 22:15

No pri tomto zapisu by to fungovalovo jen pro getElementById, kde p by mel patricne id, protoze getElements... vraci jako vysledek oindexovane objekty, kdezto v prvnim pripade je jen jeden mozny odstavec.

Hodne stesti pri reseni, se mi v zivote jeste nepovedlo nic z takovych a podobnych ustrku vyresit.

 
Odpovědět 12.6.2017 22:15
Avatar
Karel Chrobák:1. ledna 21:14

Ahoj, prosím o navedení na správnou cestu...
Mám seznam států a jejich popis. Názvy států jsou viditelné, ale jejich popis je ve výchozím stavu skrytý. Pokud klepnu na název státu, zobrazí se mi jeho popis. Tzn. klepnutím na název státu si s getElementById vyhledám příslušné pole s popisem a s setAttribute vložím do pole style="displa­y:block". To mi zobrazí popis státu. Dál už ale tápu. Pokud klepnu na další název státu, zobrazí se mi sice příslušný blok s popisem, ale ten původní zůstane zobrazen, protože tam je stále vložen style="displa­y:block". Jak bych to měl udělat, aby se mi při klepnutí na další stát skryl popis předchozího, tedy aby se z něj opět odebral atribut style="..."?
Děkuji

Odpovědět 1. ledna 21:14
Stále se učím a stále toho vím míň a míň.
Avatar
Jiří Fencl
Redaktor
Avatar
Odpovídá na Karel Chrobák
Jiří Fencl:1. ledna 21:32

Misto nastavovani primo style nastavuj unikatni tridu, skryvani vyres pres CSS definici te tridy, pak pri kliku vyhledej elementy s danou tridou, tu odstran a pridej jen aktivnimu popisku

 
Odpovědět  +1 1. ledna 21:32
Avatar
Odpovídá na Karel Chrobák
Michal Žůrek - misaz:2. ledna 9:04

buď to udělej přes třídu jak radí Jiří Fencl nebo prostě použil cykl a všechny nejprve vresetuj na display:none a teprve pak ten jeden na display:block

Odpovědět 2. ledna 9:04
Nesnáším {}, proto se jim vyhýbám.
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 30. Zobrazit vše