9. díl - Manipulace s DOM v JavaScriptu

JavaScript Základní konstrukce Manipulace s DOM v JavaScriptu

V minulém dílu jsme začali tou nejčastěji používanou metodou Domu - getElementById() a řekli jsme si něco o událostech. Tento díl bude ryze teoretický. Ukážeme si, co vše lze provádět v DOMu a v příštím díle vytvoříme již skutečně rozsáhlejší webovou aplikaci, která bude čerpat právě ze znalostí nabytých v tomto díle.

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 getElementsBy­ClassName(). Při jejím psaní si dávejte pozor, že elements je množné číslo a každé první písmeno slova (vyjímá první slovo) 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ší (značně hloupější) pole určené HTML elementům).

document.getElementsByClassName("class")

Výběr na základě tagu

Každý element má tag, což je jeho značka (typ). Metoda getElementsBy­TagName() 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 (getElementsBy­TagNameNS()). Ty ocení zejména znalci XML a vyhledávání na základě jména (getElementsBy­Name()), což se používá pro vyhledávání prvků ve formulářích, kde se ještě attribut name používá. Obě metody v případě, kdy nic nesplňuje zadané podmínky, vrátí 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 úvodní. 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ý attribut data-countdown.

Když už jsme 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 element

<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 dbát na to, že se vnitřní HTML tagy zpracují.

innerText

Podobně jako innerHTML funguje i 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. Tato vlastnost však není v oficiálním standardu, ačkoliv ve většině prohlížečů funguje, třeba v Mozille Firefox ne.

textContent

TextContent() dělá totéž co innerText(), ale na rozdíl od něj je v oficiálním standardu a měl by fungovat ve všech prohlížečích. Měli bychom tedy používat výhradně tuto vlastnost.

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 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 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>

Element form má jako potomky elementy input a button. Jinými slovy, elementy input a button jsou potomky elementu form.

Výběr potomků

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

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 od shora 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, můžeme s ním jakkoliv pracovat, ale musíme počítat s tím, ž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.

var span = document.createElement("span")
var 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 vrátí za posledního původní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, za 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 smazat 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é „srandičky“ kolem). 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 to ukotvili v paměti, si v příštím díle všechno 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. :)


 

  Aktivity (1)

Článek pro vás napsal Michal Žůrek (misaz)
Avatar
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.

Jak se ti líbí článek?
Celkem (15 hlasů) :
4.84.84.84.84.8


 



 

 

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

Avatar
tomass
Člen
Avatar
tomass:

Ok diky, ja sem to nekdy pred 3 rokama pouzival, ale od te doby sem to nevidel, tak sem si to chtel oprasit. Takze predpokladam, ze obsah treba vsech elementu muzu zmenit tak, ze si dam getElementByTag­Name("p").len­gth coz bude podminka pro velikost cyklu for a tim pak projedu vsechny elementy a pristoupim k nim podle indexu pomoci iterace.

 
Odpovědět 9.12.2015 19:08
Avatar
Odpovědět 9.12.2015 19:18
Nesnáším {}, proto se jim vyhýbám.
Avatar
Michal Remišovský:

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, za který se nový element vloží/přesune.

Není v článku chyba? Nemá tam být před?

Jinak díky za skvělé tutoriály :)

 
Odpovědět  +2 6. března 20:03
Avatar
Nezmar Hydra
Člen
Avatar
Nezmar Hydra:

snažím se přijít na to, jak si vygenorovat html kód ze scriptu.
pře innerHTML mi to jde (text a text2 je proměnná)

  • document.getE­lementById(IDec­ko).innerHTML= ("<div class=")+"pos­t"+("><h2 class=")+"title"+("><spa­n>")+text+("</span><­/h2><h3 class=")+"date"+("><span class=")+"mon­th"+(">")+tex­t2+(",-</span></h3><­/div>"); *

ale nemůžu přijít na to jak to složit přímo přes appendChild*
var trida =document.getE­lementById("Mo­jeMain3").appen­dChild(documen­t.createElemen­t("class")).class = "post";
var trida2
= trida.appendChil­d(document.cre­ateElement("clas­s")).class = "title";
trida2.appendChil­d(document.cre­ateElement("span"))­.textContent = "vnorena";*
jeden z mnoha neúspěšných pokusů.
Jde to vůbec tímto, nebo podobným způsobem?
Díky za radu

 
Odpovědět 7. října 3:13
Avatar
Michal Žůrek (misaz):

dá se to takovýám způsobem (takovým způsobem se dá úplně všechno). Pokud potřebuješ s něčím pracovat víc než 1× (např vytvořit element + nastavit mu class + nastvit mu obsah = 3 akce) musíš si ho uložit do proměnné.

var el = document.getElementById(IDecko);
var div = document.createElement("div");
div.classList.add("post");
var title = document.createElement("h2");
title.classList.add("title");
var titleSpan = document.createElement("span");
titleSpan.textContent = text;
var datum = document.createElement("h3");
datum.classList.add("date");
var month = document.createElement("span");
month.classList.add("month");
month.textContent = text2;
el.appendChild(div);
div.appendChild(title);
div.appendChild(datum);
title.appendChild(titleSpan);
datum.appendChild(month);
Odpovědět 8. října 0:08
Nesnáším {}, proto se jim vyhýbám.
Avatar
Nezmar Hydra
Člen
Avatar
Odpovídá na Michal Žůrek (misaz)
Nezmar Hydra:

Děkuji. To už jsem pořešil ochotně poradil mi ve fotu Ján Timoranský. Nejvíc zapečenej pes byl v tom, že jsem neustále používal blbě element.clas ="jgjhg" místo element.clasName = "fgdf". Jak mě natrk tak už jsem na to přišel. A pak mi ještě napsal kódik, ze kterýho jsem pochopil další niance. a udělal to taklenc:

function NewBody (IDecko,Hlavic­ka,Datum,Telo){
var post = document.crea­teElement("div");
var title = document.crea­teElement("h2");
var date = document.crea­teElement("h3");
var story = document.crea­teElement("div");

post.className = "post";
title.className = "title";
date.className = "date";
story.className = "story";

document.getE­lementById("ma­in").appendChil­d(document.cre­ateElement("ID"))­.id = (IDecko);
var element = document.getE­lementById(IDec­ko).appendChil­d(post);

element.appen­dChild(title)­.appendChild(do­cument.create­Element("span"))­.textContent= (Hlavicka);
element.appen­dChild(date).ap­pendChild(docu­ment.createEle­ment("span"))­.textContent= (Datum);

element.appen­dChild(story)­.appendChild(do­cument.create­Element("p"))­.textContent= (Telo);

}

Editováno 8. října 1:41
 
Odpovědět 8. října 1:39
Avatar
Jirka
Člen
Avatar
Jirka:

Ahoj mám problém, nezobrazuje se mi ani podle návodů zde kód:

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

nic mi to nedělá, dále se chci zeptat, jestli má vliv, když mám externí soubor .js odkazovaný v <head> než když dám script pod <body>?

Děkuji

J

 
Odpovědět 22. listopadu 11:45
Avatar
Odpovídá na Jirka
Michal Žůrek (misaz):

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. listopadu 12:24
Nesnáším {}, proto se jim vyhýbám.
Avatar
Jirka
Člen
Avatar
Odpovídá na Michal Žůrek (misaz)
Jirka:

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. listopadu 12:34
Avatar
Michal Žůrek (misaz):
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. listopadu 19:41
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 23. Zobrazit vše