Dom je objektový model dokumentu. Expressive JavaScript: Document Object Model


Struktura dokumentu

HTML si můžete představit jako řadu vnořených polí. Zdá se, že štítky obsahují další štítky, které zase obsahují štítky nebo text. Zde je příklad dokumentu z předchozí kapitoly:

Moje domovská stránka Moje domovská stránka

Ahoj, jmenuji se Marijn a toto je moje domovská stránka.

A taky jsem napsal knihu! Přečtěte si to zde.

Tato stránka má následující strukturu:

Struktura dat, kterou prohlížeč používá k prezentaci dokumentu, odráží jeho formu. Pro každý box je objekt, se kterým můžeme interagovat a zjišťovat o něm různá data – jakou značku představuje, jaké pole a text obsahuje. Tato reprezentace se nazývá Document Object Model ( objektový model dokument) nebo zkráceně DOM.

K těmto objektům můžeme přistupovat prostřednictvím globální proměnné dokumentu. Jeho vlastnost documentElement odkazuje na objekt představující značku. Poskytuje také vlastnosti hlavy a těla, které obsahují objekty pro odpovídající prvky.

Stromy Připomeňme si syntaktické stromy z kapitoly 11. Jejich struktura je nápadně podobná struktuře dokumentu prohlížeče. Každý uzel se může propojit s jinými uzly a každá větev může mít svou vlastní větev. Tato struktura je typickým příkladem vnořených struktur, kde prvky obsahují dílčí prvky podobné jim samotným.

Datovou strukturu nazýváme strom, když se větví, nemá žádné smyčky (uzel nemůže obsahovat sám sebe) a má jeden odlišný „kořen“. V případě DOM je kořenem document.documentElement.

Stromy se často vyskytují ve výpočetní vědě. Kromě reprezentace rekurzivních struktur, jako jsou dokumenty HTML nebo programy, se často používají pro práci s seřazenými sadami dat, protože prvky se obvykle snáze hledají nebo vkládají do setříděného stromu než do setříděného jednorozměrného pole.

Typický strom má různé uzly. Strom syntaxe jazyka Egg měl proměnné, hodnoty a aplikace. Aplikace vždy měly podřízené větve a proměnné a hodnoty byly „listy“, tedy uzly bez podřízených větví.

Totéž platí pro DOM. Uzly pro běžné prvky, představující HTML tagy, definují strukturu dokumentu. Mohou mít podřízené uzly. Příkladem takového uzlu je document.body. Některé z těchto podřízených uzlů mohou být listy, jako je text nebo komentáře (v HTML se komentáře píší mezi znaky).

Každý objekt uzlu DOM má vlastnost nodeType, která obsahuje číselný kód, který identifikuje typ uzlu. Pro regulární prvky se rovná 1, což je také definováno jako konstantní vlastnost document.ELEMENT_NODE. Textové uzly představující textové pasáže mají hodnotu 3 (document.TEXT_NODE). Komentáře mají 8 (document.COMMENT_NODE).

To znamená, že zde je další způsob, jak graficky znázornit strom dokumentu:

Listy jsou textové uzly a šipky ukazují vztahy otce a potomka mezi uzly.

Standardní Použití tajemných čísel k reprezentaci typu uzlu není přístup ve stylu JavaScriptu. Později se setkáme s dalšími částmi rozhraní DOM, které také působí cize a neohrabaně. Důvodem je, že DOM nebyl navržen pouze pro JavaScript. Pokouší se definovat jazykově nezávislé rozhraní, které lze použít v jiných systémech – nejen HTML, ale také XML, což je obecný datový formát se syntaxí podobnou HTML.

Ukazuje se to jako nepohodlné. I když normy jsou docela užitečná věc, v našem případě není výhoda jazykové nezávislosti tak užitečná. Je lepší mít rozhraní, které je dobře přizpůsobené jazyku, který používáte, než rozhraní známé napříč jazyky.

Chcete-li ilustrovat nepohodlnou integraci s jazykem, zvažte vlastnost childNodes, kterou mají uzly DOM. Obsahuje objekt podobný poli s vlastností length a číslovanými vlastnostmi pro přístup k podřízeným uzlům. Ale toto je instance typu NodeList, nikoli skutečné pole, takže nemá metody jako forEach.

Existují také problémy spojené se špatným návrhem systému. Nemůžete například vytvořit nový uzel a okamžitě k němu přidat vlastnosti nebo podřízené uzly. Nejprve jej musíte vytvořit, poté přidávat děti po jednom a nakonec přiřazovat vlastnosti po jednom pomocí vedlejších efektů. Kód, který úzce spolupracuje s DOM, se ukazuje jako dlouhý, nevzhledný a s velkým množstvím opakování.

Tyto problémy ale nejsou fatální. JavaScript umožňuje vytvářet abstrakce. Snadno psát sekundární funkce, což umožňuje, aby operace byly vyjádřeny jasněji a stručněji. Obecně tyto druhy nástrojů poskytují mnoho knihoven zaměřených na programování pro prohlížeč.

Uzly DOM pro procházení stromu obsahují mnoho odkazů na sousední uzly. To je znázorněno na diagramu:

Ačkoli je zde zobrazen pouze jeden odkaz každého typu, každý uzel má vlastnost parentNode odkazující na jeho nadřazený uzel. Každý uzel prvku (typ 1) má také vlastnost childNodes, která ukazuje na objekt podobný poli obsahující jeho podřízené uzly.

Teoreticky můžete přejít do jakékoli části stromu pouze pomocí těchto odkazů. JavaScript nám však poskytuje mnoho dalších pomocných odkazů. Vlastnosti firstChild a lastChild ukazují na první a poslední podřízený prvek nebo jsou null pro ty uzly, které nemají žádné potomky. previousSibling a nextSibling ukazují na sousední uzly – uzly, které mají stejného rodiče jako aktuální uzel, ale jsou bezprostředně před nebo za aktuálním uzlem v seznamu. Vlastnost previousSibling prvního uzlu bude null a vlastnost nextSibling posledního uzlu bude null.

Při práci s takto vnořenými strukturami se hodí rekurzivní funkce. Následující text vyhledá v dokumentu textové uzly obsahující daný řetězec a vrátí hodnotu true, když jej najde:

Funkce talksAbout(node, string) ( if (node.nodeType == document.ELEMENT_NODE) ​​​​( for (var i = 0; i< node.childNodes.length; i++) { if (talksAbout(node.childNodes[i], string)) return true; } return false; } else if (node.nodeType == document.TEXT_NODE) { return node.nodeValue.indexOf(string) >-1;

) ) console.log(talksAbout(document.body, "books")); // → pravda

Vlastnosti textového uzlu nodeValue obsahuje řádek textu.

Hledání prvků Často je užitečné procházet těmito nadřazenými, podřízenými a sourozeneckými odkazy a procházet celým dokumentem. Pokud však potřebujeme konkrétní uzel v dokumentu, je velmi nepohodlné jej procházet, začínat od document.body a hloupě procházet cestou pevně zakódovanou v kódu. Tím vytváříme do programu předpoklady o přesné struktuře dokumentu – které můžeme později chtít změnit. Dalším komplikujícím faktorem je, že textové uzly jsou vytvářeny i pro mezery mezi uzly. V dokumentu z příkladu nemá značka body tři potomky (h1 a dvě p), ale sedm: tyto tři plusové mezery před, za a mezi nimi.

Var link = document.body.getElementsByTagName("a"); console.log(link.href);

Všechny uzly prvků mají metodu getElementsByTagName, která shromažďuje všechny prvky s danou značkou, které jsou potomky (přímými nebo nepřímými potomky) tohoto uzlu, a vrací je jako objekt podobný poli.

Chcete-li najít konkrétní uzel, můžete mu přiřadit atribut id a použít metodu document.getElementById.

var pštros = document.getElementById("gertrude"); console.log(ostrich.src);

Třetí metodou je getElementsByClassName, která stejně jako getElementsByTagName prohledává obsah uzlu prvku a vrací všechny prvky, které obsahují zadaný řetězec ve své třídě.

Změna dokumentu Téměř vše ve struktuře DOM lze změnit. Uzly prvků mají sadu metod, které se používají k jejich úpravě. Metoda removeChild odebere zadaný podřízený uzel. Chcete-li přidat uzel, můžete použít appendChild, který přidá uzel na konec seznamu, nebo insertBefore, který přidá uzel předaný jako první argument před uzel předaný jako druhý argument.

var odstavce = document.body.getElementsByTagName("p"); document.body.insertBefore(odstavce, odstavce);

Uzel může existovat pouze na jednom místě v dokumentu. Takže vložením odstavce „Tři“ před odstavec „Jedna“ jej vlastně odstraníme z konce seznamu a vložíme na začátek a dostaneme „Tři/Jedna/Dva“. Všechny operace pro vložení uzlu povedou k jeho zmizení z jeho aktuální pozice (pokud nějakou měl).

Metoda replaceChild se používá k nahrazení jednoho podřízeného uzlu jiným. Přijímá dva uzly: nový a ten, který je třeba vyměnit. Uzel, který má být nahrazen, musí být potomkem prvku, jehož metodu voláme. ReplaceChild i insertBefore očekávají jako první argument nový uzel.

Vytváření uzlů V následujícím příkladu musíme vytvořit skript, který nahradí všechny obrázky (tag) v dokumentu textem obsaženým v jejich atributu „alt“, který určuje alternativní textovou reprezentaci obrázku.

Chcete-li to provést, musíte obrázky nejen odstranit, ale také přidat nové textové uzly, které je nahradí. K tomu používáme metodu document.createTextNode.

Tento PROTI .

Nahradit

function replaceImages() ( var images = document.body.getElementsByTagName("img"); for (var i = images.length - 1; i >= 0; i--) ( var image = images[i]; if ( image.alt) ( var text = document.createTextNode(image.alt); image.parentNode.replaceChild(text, image); ) ) )

Zadaný řetězec nám createTextNode poskytne uzel DOM typu 3 (text), který můžeme vložit do dokumentu a zobrazit jej na obrazovce.

Cyklus mezi obrázky začíná na konci seznamu uzlů. To se děje proto, že seznam uzlů vrácených metodou getElementsByTagName (nebo vlastností childNodes) se neustále aktualizuje, jak se dokument mění. Pokud bychom začali od začátku, odstranění prvního obrázku by způsobilo, že by seznam ztratil svůj první prvek a během druhého průchodu smyčkou, kdy i je 1, by se zastavil, protože délka seznamu by také byla 1.

Pokud potřebujete pracovat s pevným seznamem uzlů namísto živého, můžete jej převést na skutečné pole pomocí metody slice.

Var arrayish = (0: "jedna", 1: "dva", délka: 2); var real = Array.prototype.slice.call(arrayish, 0); real.forEach(function(elt) ( console.log(elt); )); // → jeden // dva

Chcete-li vytvořit uzly prvku (typ 1), můžete použít document.createElement. Metoda převezme název značky a vrátí nový prázdný uzel daný typ. Následující příklad definuje nástroj elt, který vytvoří uzel prvku a použije zbývající argumenty jako své potomky. Tato funkce se pak používá k přidání dalších informací do nabídky.

Žádná kniha není nikdy dokončena. Při práci na něm se naučíme dost na to, abychom jej zjistili, že je nezralý, jakmile ho opustíme. funkce elt(typ) ( var node = document.createElement(type); for (var i = 1; i< arguments.length; i++) { var child = arguments[i]; if (typeof child == "string") child = document.createTextNode(child); node.appendChild(child); } return node; } document.getElementById("quote").appendChild(elt("footer", "-", elt("strong", "Карл Поппер"), ", предисловие ко второму изданию ", elt("em", "Открытое общество и его враги "), ", 1950"));

Atributy Některé prvky atributů, například href pro odkazy, jsou přístupné prostřednictvím stejnojmenné vlastnosti object. To je možné u omezeného počtu běžně používaných standardních atributů.

HTML ale umožňuje přiřadit uzlům libovolné atributy. To je užitečné, protože... umožňuje uložit další informace do dokumentu. Pokud si vymyslíte vlastní názvy atributů, nebudou mezi vlastnostmi uzlu prvku. Místo toho budete muset použít metody getAttribute a setAttribute, abyste s nimi mohli pracovat.

Startovací kód 00000000.

Kočka má čtyři nohy.

var paras = document.body.getElementsByTagName("p"); Array.prototype.forEach.call(paras, function(para) ( if (para.getAttribute("data-classified") == "secret") para.parentNode.removeChild(para; ));

Doporučuji před názvy vymyšlených atributů uvést „data-“, aby nebyly v rozporu s jinými. Tak jako jednoduchý příklad Napíšeme zvýrazňovač syntaxe, který hledá značky („předformátovaný“ – používá se pro kód a prostý text) s atributem data-language a poměrně hrubě se snaží zvýraznit klíčová slova v jazyce.

Funkce highlightCode(node, keywords) ( var text = node.textContent; node.textContent = ""; // Vymazání shody var uzlu, pos = 0; while (match = keywords.exec(text)) ( var before = text SLICE (POS, Match.Index) keywords.lastIndex ) var after = text.slice(pos);appendChild(document.createTextNode(after));

Funkce highlightCode přebírá uzel A běžný znak (s povoleným globálním nastavením), který odpovídá klíčovému slovu programovacího jazyka, které obsahuje prvek.

Vlastnost textContent se používá k získání veškerého textu uzlu a je pak nastavena na prázdný řetězec, čímž se uzel vymaže. Procházíme všechny výskyty klíčového slova, přidáváme mezi ně text ve formě jednoduchých textových uzlů a přidáváme odpovídající text (klíčová slova) tak, že je uzavřeme do prvků (tučně).

Můžeme automaticky zvýraznit celý kód stránky procházením všech prvků, které mají atribut data-language, a voláním highlightCode u každého se správným regulárním výrazem.

Var languages ​​​​= ( javascript: /\b(funkce|return|var)\b/g /* … atd */ ); funkce highlightAllCode() ( var pres = document.body.getElementsByTagName("pre"); for (var i = 0; i< pres.length; i++) { var pre = pres[i]; var lang = pre.getAttribute("data-language"); if (languages.hasOwnProperty(lang)) highlightCode(pre, languages); } }

Zde je příklad:

A tady je identifikační funkce:

Funkce id(x) ( return x; ) highlightAllCode();

Existuje jeden běžně používaný atribut, class, jehož název je klíčové slovo v JavaScriptu. Z historických důvodů, kdy starší implementace JavaScriptu nebyly schopny zpracovat názvy vlastností, které se shodovaly klíčová slova, je tento atribut přístupný prostřednictvím vlastnosti nazvané className. Můžete k němu také přistupovat pod jeho skutečným názvem „class“ prostřednictvím metod getAttribute a setAttribute.

Rozložení Možná jste si všimli, že různé typy prvků jsou rozmístěny odlišně. Některé, jako odstavce

Nadpisy se táhnou přes celou šířku dokumentu a zobrazují se na samostatných řádcích. Takové prvky se nazývají blokové prvky. Ostatní jako odkazy nebo se tučný text objeví na stejném řádku jako okolní text. Říká se jim vestavěné (inline).

Pro jakýkoli dokument mohou prohlížeče vytvořit uspořádání prvků, rozvržení, ve kterém bude mít každý velikost a polohu podle svého typu a obsahu. Toto rozvržení se pak použije k vytvoření vzhledu dokumentu.

Velikost a pozici prvku lze zjistit pomocí JavaScriptu. Vlastnosti offsetWidth a offsetHeight udávají velikost v pixelech obsazených prvkem. Pixel je základní měrnou jednotkou v prohlížečích a obvykle odpovídá velikosti nejmenšího bodu na obrazovce. Podobně clientWidth a clientHeight udávají velikost vnitřku prvku, nepočítaje ohraničení (nebo, jak někteří říkají, obrubník).

Jsem v krabici

var para = document.body.getElementsByTagName("p"); console.log("clientHeight:", para.clientHeight); console.log("offsetHeight:", para.offsetHeight);

Nejúčinnějším způsobem, jak zjistit přesné umístění prvku na obrazovce, je metoda getBoundingClientRect. Vrací objekt s vlastnostmi top, bottom, left a right, které obsahují polohu prvku vzhledem k levému hornímu rohu obrazovky v pixelech. Pokud potřebujete získat tato data vzhledem k celému dokumentu, musíte přidat aktuální pozici posouvání, která je obsažena v globálních proměnných pageXOffset a pageYOffset.

Analýza dokumentu je obtížný úkol. Z důvodu rychlosti motory prohlížeče nepřestavují dokument při každé změně, ale počkají tak dlouho. jak je tohle možné. Když program JavaScript, který upravil dokument, skončí, prohlížeč bude muset vypočítat nové rozvržení stránky, aby se upravený dokument zobrazil na obrazovce. Když program požaduje polohu nebo velikost něčeho čtením vlastností, jako je offsetHeight nebo voláním getBoundingClientRect, musí být rozložení také vypočteno, aby poskytovalo správné informace.

Program, který periodicky čte rozvržení DOM a upravuje DOM, donutí prohlížeč mnohokrát rozvržení přepočítat, a proto bude pomalý. V následujícím příkladu jsou dva různé programy, které vytvoří řádek o šířce 2000 px širokých X znaků a měří dobu běhu.

function time(name, action) ( var start = Date.now(); // Aktuální čas v milisekundách action(); console.log(name, "takeen", Date.now() - start, "ms"); ) time("dumb", function() ( var target = document.getElementById("one"); while (target.offsetWidth< 2000) target.appendChild(document.createTextNode("X")); }); // → тупо заняло 32 ms time("умно", function() { var target = document.getElementById("two"); target.appendChild(document.createTextNode("XXXXX")); var total = Math.ceil(2000 / (target.offsetWidth / 5)); for (var i = 5; i < total; i++) target.appendChild(document.createTextNode("X")); }); // → умно заняло 1 ms

Styly Viděli jsme, že různé prvky HTML se chovají odlišně. Některé jsou zobrazeny jako bloky, jiné jsou vložené. Některé přidávají vizuální styl, například text tučným a podtrženým a modrým.

Vzhled obrázku v tagu nebo to, že odkaz v tagu po kliknutí otevře novou stránku, souvisí s typem prvku. Ale základní styly spojené s prvkem, jako je barva textu nebo podtržení, můžeme změnit. Zde je příklad použití vlastnosti style:

Zelený odkaz

Atribut style může obsahovat jednu nebo více deklarací vlastnosti (barva), za nimiž následuje dvojtečka a hodnota. V případě více deklarací se oddělují středníkem: „color: red; hranice: žádná".

Pomocí stylů lze změnit spoustu věcí. Vlastnost zobrazení například řídí, zda je prvek zobrazen v blokové nebo vložené formě.

Text je zobrazen jako blok a není vůbec viditelný.

Prvek bloku je zobrazen jako samostatný blok a druhý blok není vůbec viditelný – display: none deaktivuje zobrazení prvků. Tímto způsobem můžete skrýt prvky. To je obvykle preferováno úplné odstranění z dokumentu, protože je snazší je později v případě potřeby znovu zobrazit.

Kód JavaScript může přímo působit na styl prvku prostřednictvím vlastnosti stylu uzlu. Obsahuje objekt, který má vlastnosti pro všechny vlastnosti stylu. Jejich hodnoty jsou řetězce, do kterých můžeme zapisovat, abychom změnili nějaký aspekt stylu prvku.

Krása

var para = document.getElementById("para"); console.log(para.style.color); para.style.color = "purpurová";

Některé názvy vlastností stylu obsahují spojovníky, například font-family. Protože by se s nimi v JavaScriptu nepohodlně pracovalo (museli byste napsat style["font-family"]), jsou názvy vlastností v objektu stylu psány bez pomlčky, ale místo toho se v nich objevují velká písmena: style.fontFamily

Kaskádové styly Systém stylů v HTML se nazývá CSS (Cascading Style Sheets). Šablona stylů je sada stylů v dokumentu. Může být zapsán do značky:
silné (styl písma: kurzíva; barva: šedá; )

Nyní je text silné značky nakloněný a šedý.

"Kaskádové" znamená, že se zkombinuje více pravidel, aby se vytvořil konečný styl dokumentu. V příkladu je výchozí styl pro, který činí text tučným, překryt pravidlem ze značky, které přidává styl a barvu písma.

Pokud je hodnota vlastnosti určena více než jedním pravidlem, mají přednost ta pozdější. Pokud by styl textu zahrnoval pravidlo tloušťka písma: normální, které je v konfliktu s výchozím stylem, pak by byl text normální, nikoli tučný. Styly, které jsou aplikovány na uzel prostřednictvím atributu style, mají nejvyšší prioritu.

V CSS je možné nastavit nejen název tagů. Pravidlo pro .abc platí pro všechny prvky, které mají specifikovanou třídu „abc“. Pravidlo #xyz se vztahuje na prvek s atributem id rovným „xyz“ (atributy id musí být jedinečné pro daný dokument).

Jemné ( barva: šedá; velikost písma: 80 %; ) #header ( pozadí: modrá; barva: bílá; ) /* Prvky p, které mají třídy aab a id nastavené na hlavní */ p.a.b#main ( margin-bottom : 20px)

Priorita nejnovějších pravidel funguje, když mají pravidla stejnou granularitu. Je to míra toho, jak přesně popisuje způsobilé prvky, určená počtem a typem požadovaných prvků. Například pravidlo pro p.a je podrobnější než pravidla pro p nebo just.a a bude mít přednost.

Zápis p > a (...) platí pro všechny tagy, které jsou uvnitř tagu a jsou jeho přímými potomky.
p a (...) platí také pro všechny tagy v rámci, ať už jde o přímé potomky nebo ne.

Selektory dotazů V této knize příliš nepoužíváme šablony stylů. Pochopení toho, jak fungují, je pro programování prohlížeče zásadní, ale podrobné vysvětlení všech jejich vlastností by zabralo 2-3 knihy. hlavní důvod seznámení se s nimi a se syntaxí selektorů (záznamů, které určují, na které prvky se pravidla vztahují) – stejně účinný minijazyk můžeme použít k vyhledávání prvků DOM.

Metoda querySelectorAll, která existuje jak na objektu dokumentu, tak na prvcích uzlu, vezme řetězec selektoru a vrátí objekt podobný poli obsahující všechny prvky, které mu odpovídají.

Miluji bouři na začátku května

Když první jarní hřmění

Jako by frčel a hrál si

Dunění na modré obloze.

funkce pocet(selektor) ( return document.querySelectorAll(selector).length; ) console.log(count("p")); // Všechny prvky

// → 4 console.log(count(".animal")); // Třída zvířat // → 2 console.log(count("p .animal")); // Třída zvířat uvnitř

// → 2 console.log(count("p > .animal")); // Přímé dítě

// → 1

Na rozdíl od metod jako getElementsByTagName není objekt vrácený querySelectorAll interaktivní. Pokud dokument změníte, nezmění se.

Podobně funguje metoda querySelector (bez All). Potřebujete to, pokud potřebujete jeden konkrétní prvek. Vrátí pouze první shodu, nebo null, pokud nejsou žádné shody.

Pozice a animace Vlastnost position stylů výrazně ovlivňuje umístění prvků. Ve výchozím nastavení je statický, což znamená, že prvek je v dokumentu ve své normální poloze. Když je relativní, prvek stále zabírá místo, ale nyní lze použít vlastnosti nahoře a vlevo k jeho posunutí vzhledem k jeho normální poloze. Když je absolutní, prvek je odstraněn z běžného „toku“ dokumentu – to znamená, že nezabírá místo a může se překrývat s ostatními. Kromě toho lze jeho vlastnosti left a top použít k umístění absolutně vzhledem k levému hornímu rohu nejbližšího uzavíracího prvku, jehož poloha není statická. A pokud takový prvek neexistuje, je umístěn vzhledem k dokumentu.

Můžeme to použít k vytvoření animace. Následující dokument ukazuje obrázek kočky pohybující se po elipse.

var cat = document.querySelector("img"); var úhel = 0, lastTime = null; function animate(time) ( if (lastTime != null) angle += (time - lastTime) * 0,001; lastTime = time; cat.style.top = (Math.sin(angle) * 20) + "px"; cat .style.left = (Math.cos(úhel) * 200) + "px"; requestAnimationFrame(animate);

Obrázek je vycentrován na stránce a má danou pozici: relativní. Neustále aktualizujeme horní a levé vlastnosti obrázku, aby se mohl pohybovat.

Skript používá requestAnimationFrame k volání funkce animace pokaždé, když je prohlížeč připraven překreslit obrazovku. Samotná funkce animace znovu volá requestAnimationFrame, aby naplánovala další aktualizaci. Když je okno prohlížeče (nebo záložka) aktivní, bude to mít za následek aktualizace rychlostí přibližně 60krát za sekundu, což umožňuje pěkně vypadající animace.

Pokud bychom jednoduše aktualizovali DOM ve smyčce, stránka by zamrzla a nic by nebylo vidět. Prohlížeče neobnovují stránku, když je spuštěn JavaScript, a neumožňují interakci se stránkou, když je spuštěna. To je důvod, proč potřebujeme requestAnimationFrame – říká prohlížeči, že jsme pro tuto chvíli hotovi, a může provádět věci svého prohlížeče, jako je obnovovat obrazovku a reagovat na požadavky uživatelů.

Naše animační funkce předává aktuální čas přes argumenty, které porovnává s předchozím (proměnná lastTime), aby byl pohyb kočky rovnoměrný a animace probíhala plynule. Pokud bychom s ním v každém kroku jednoduše pohnuli o nastavenou hodnotu, pohyb by se zpomalil, pokud by například počítač zatížil jiný úkol.

Kruhový pohyb se provádí pomocí goniometrických funkcí Math.cos a Math.sin. Pro ty, kteří je neznají, je krátce popíšu, protože je budeme potřebovat později.

Math.cos a Math.sin jsou užitečné, když potřebujete najít body na kružnici se středem v (0, 0) a poloměrem jedna. Obě funkce interpretují svůj argument jako polohu na kružnici, kde 0 je bod na pravém okraji kružnice, pak proti směru hodinových ručiček, dokud nás dráha 2π (asi 6,28) nezavede po kružnici. Math.cos vypočítá souřadnici x bodu, který je naší aktuální pozicí na kružnici, a Math.sin udává souřadnici y. Pozice (nebo úhly) větší než 2π nebo menší než 0 jsou také povoleny - rotace se opakují tak, že a+2π znamená stejný úhel jako a.

Použití sinusu a kosinu k výpočtu souřadnic Animace kočky ukládá čítač úhlů pro aktuální úhel natočení animace a zvyšuje jej úměrně k uplynulému času při každém vyvolání funkce animace. Tento úhel se používá k výpočtu aktuální polohy obrazového prvku. Horní styl se vypočítá pomocí Math.sin a vynásobí se 20 - to je vertikální poloměr naší elipsy. Levý styl se vypočítá přes Math.cos a vynásobí se 200, takže šířka elipsy je mnohem větší než výška.

Styly obvykle vyžadují jednotky měření. V našem případě musíme k číslu přidat px, abychom prohlížeči vysvětlili, že počítáme v pixelech (a ne v centimetrech, ems nebo jiných jednotkách). Je snadné zapomenout. Použití čísel bez jednotek způsobí, že styl bude ignorován - pokud číslo není 0, což je nezávislé na jednotkách.

Shrnutí Programy JavaScript mohou zkoumat a upravovat aktuálně zobrazený dokument v prohlížeči prostřednictvím struktury zvané DOM. Tato datová struktura představuje model dokumentu prohlížeče a program JavaScript ji může upravit tak, aby změnil viditelný dokument. DOM je organizován jako strom, ve kterém jsou prvky uspořádány hierarchicky podle struktury dokumentu. Objekty prvků mají vlastnosti typu parentNode a childNodes, které slouží k orientaci ve stromu.

Vzhled dokumentu lze změnit pomocí stylů, buď přímým přidáním stylů do uzlů, nebo definováním pravidel pro některé uzly. Styly mají mnoho vlastností, jako je barva nebo zobrazení. JavaScript může ovlivnit styl prvku přímo prostřednictvím jeho vlastnosti stylu.

Cvičení Sestavení tabulky Tabulky jsme vytvořili z prostého textu v kapitole 6. HTML usnadňuje vytváření tabulek. Tabulka v HTML je vytvořena pomocí následujících značek:

jméno výška země
Kilimandžáro 5895 Tanzanie

Každý řádek obsahuje značku. Uvnitř můžeme umístit buňky: buď buňky záhlaví nebo běžné buňky.

Stejná data, která jsme použili v kapitole 6, jsou opět dostupná v proměnné MOUNTAINS.

Napište funkci buildTable, která pomocí pole objektů se stejnými vlastnostmi vytvoří strukturu DOM představující tabulku. Tabulka by měla mít řádek záhlaví, kde jsou názvy vlastností zabaleny do prvků, a na každý objekt pole by měl být jeden řádek, kde jsou jeho vlastnosti zabaleny do prvků. Zde se hodí funkce Object.keys, která vrací pole obsahující názvy vlastností objektu.

Jakmile budete mít základy, zarovnejte buňky s čísly doprava změnou jejich vlastnosti style.textAlign na "right".

/* Definuje styly pro krásné tabulky */ tabulka ( border-collapse: Collapse; ) td, th ( border: 1px plná černá; padding: 3px 8px; ) th ( text-align: left; ) function buildTable(data) ( / / Váš kód ) document.body.appendChild(buildTable(MOUNTAINS));

Elementy podle názvu tagu Metoda getElementsByTagName vrací všechny podřízené elementy s daným názvem tagu. Vytvořte si vlastní verzi této metody jako běžnou funkci, která vezme uzel a řetězec (název značky) a vrátí pole obsahující všechny sestupné uzly s daným názvem značky.

Chcete-li zjistit název tagu prvku, použijte vlastnost tagName. Všimněte si, že to vrátí název značky velkými písmeny. Použijte řetězcové metody toLowerCase nebo toUpperCase.

Název s prvkem span uvnitř.

Odstavec s jedním nebo dvěma prvky spans.

function byTagName(uzel, tagName) ( // Váš kód ) console.log(byTagName(document.body, "h1").length); // → 1 console.log(byTagName(document.body, "span").length); // → 3 var para = document.querySelector("p"); console.log(byTagName(para, "span").length); // → 2

Cat's Hat Rozbalte animaci kočky tak, aby kočka i její klobouk létaly na opačných stranách elipsy.

Nebo nechte klobouk létat kolem kočky. Nebo vymyslete něco jiného zajímavého.

Pro zjednodušení uspořádání mnoha objektů je dobré přejít na absolutní umístění. Horní a levý pak budou považovány za relativní k levému hornímu rohu dokumentu. Chcete-li se vyhnout použití záporných souřadnic, můžete k hodnotám polohy přidat daný počet pixelů.

var cat = document.querySelector("#cat"); var klobouk = document.querySelector("#klobouk"); // Váš kód zde.

Vývojáři obvykle používají jQuery, když potřebují něco udělat s DOM. Téměř jakoukoli manipulaci s DOM však lze provést v čistém JavaScriptu pomocí jeho DOM API.

Podívejme se na toto API podrobněji:

Nakonec si napíšete vlastní jednoduchou DOM knihovnu, kterou lze použít v jakémkoli projektu.

Dotazy DOM

Dotazy DOM se provádějí pomocí metody .querySelector(), která jako argument používá libovolný selektor CSS.

Const myElement = document.querySelector("#foo > div.bar")

Vrátí první odpovídající prvek. Můžete to udělat naopak - zkontrolujte, zda prvek odpovídá selektoru:

MyElement.matches("div.bar") === true

Pokud chcete získat všechny prvky, které odpovídají selektoru, použijte následující konstrukci:

Const myElements = document.querySelectorAll(.bar")

Pokud víte, na který nadřazený prvek chcete odkazovat, můžete místo prohledávání celého kódu jednoduše prohledávat jeho potomky:

Const myChildElemet = myElement.querySelector("input") // Místo: // document.querySelector("#foo > div.bar input")

Nabízí se otázka: proč potom používat jiné, méně pohodlné metody jako .getElementsByTagName() ? Je tu malý problém - výstupní výsledek .querySelector() není aktualizován a když přidáme nový prvek(viz), nezmění se.

Const elements1 = document.querySelectorAll("div") const elements2 = document.getElementsByTagName("div") const newElement = document.createElement("div") document.body.appendChild(newElement) elements1.length === elements2.length // Nepravdivé

Také querySelectorAll() shromažďuje vše do jednoho seznamu, takže není příliš efektivní.

Jak pracovat se seznamy?

Kromě toho má .querySelectorAll() dvě malá upozornění. Nemůžete jen volat metody na výsledky a očekávat, že budou aplikovány na každý z nich (jako jste možná zvyklí dělat s jQuery). V každém případě budete muset iterovat všechny prvky ve smyčce. Za druhé, vrácený objekt je seznam prvků, nikoli pole. Metody pole proto nebudou fungovat. Samozřejmě existují metody pro seznamy, něco jako .forEach() , ale bohužel nejsou vhodné pro všechny případy. Takže je lepší převést seznam na pole:

// Použití Array.from() Array.from(myElements).forEach(doSomethingWithEachElement) // Nebo prototyp pole (před ES6) Array.prototype.forEach.call(myElements, doSomethingWithEachElement) // Jednodušší: .forEach.call( myElements , doSomethingWithEachElement)

Každý prvek má nějaké vlastnosti, které odkazují na "rodinu".

MyElement.children myElement.firstElementChild myElement.lastElementChild myElement.previousElementSibling myElement.nextElementSibling

Vzhledem k tomu, že rozhraní prvku je zděděno z rozhraní Node, jsou k dispozici také následující vlastnosti:

MyElement.childNodes myElement.firstChild myElement.lastChild myElement.previousSibling myElement.nextSibling myElement.parentNode myElement.parentElement

První vlastnosti odkazují na prvek a poslední (s výjimkou .parentElement) mohou být seznamy prvků libovolného typu. Podle toho můžete zkontrolovat typ prvku:

MyElement.firstChild.nodeType === 3 // tento prvek bude textový uzel

Přidání tříd a atributů

Přidat nová třída velmi jednoduché:

MyElement.classList.add("foo") myElement.classList.remove("bar") myElement.classList.toggle("baz")

Přidání vlastnosti k prvku je stejné jako u jakéhokoli objektu:

// Získání hodnoty atributu const value = myElement.value // Nastavení atributu jako vlastnosti prvku myElement.value = "foo" // Для установки нескольких свойств используйте.Object.assign() Object.assign(myElement, { value: "foo", id: "bar" }) // Удаление атрибута myElement.value = null !}

Můžete použít metody .getAttibute() , .setAttribute() a .removeAttribute(). Okamžitě změní atributy HTML prvku (na rozdíl od vlastností DOM), což způsobí opětovné vykreslení prohlížeče (všechny změny můžete vidět prozkoumáním prvku pomocí vývojářských nástrojů prohlížeče). Taková překreslování nejen vyžadují více prostředků než nastavení vlastností DOM, ale mohou také vést k neočekávaným chybám.

Obvykle se používají pro prvky, které nemají odpovídající vlastnosti DOM, jako je colspan . Nebo jestli je jejich použití opravdu nutné, například pro HTML vlastnosti při dědění (viz).

Přidání stylů CSS

Přidávají se stejným způsobem jako ostatní vlastnosti:

MyElement.style.marginLeft = "2em"

Některé specifické vlastnosti lze nastavit pomocí .style , ale pokud chcete získat hodnoty po některých výpočtech, pak je lepší použít window.getComputedStyle() . Tato metoda přijme prvek a vrátí CSSStyleDeclaration obsahující styly samotného prvku i jeho rodiče:

Window.getComputedStyle(myElement).getPropertyValue("margin-left")

Změna DOM

Prvky můžete přesouvat:

// Připojit element1 jako posledního potomka elementu2 element1.appendChild(element2) // Vložit element2 jako potomka elementu1 před element3 element1.insertBefore(element2, element3)

Pokud jej nechcete přesunout, ale potřebujete vložit kopii, použijte:

// Vytvořte klon const myElementClone = myElement.cloneNode() myParentElement.appendChild(myElementClone)

Metoda .cloneNode() přebírá jako argument booleovskou hodnotu, a pokud je true, podřízené prvky jsou také klonovány.

Samozřejmě můžete vytvářet nové prvky:

Const myNewElement = document.createElement("div") const myNewTextNode = document.createTextNode("nějaký text")

A poté je vložte, jak je znázorněno výše. Prvek nelze odstranit přímo, ale můžete to udělat prostřednictvím nadřazeného prvku:

MyParentElement.removeChild(myElement)

Můžete také nepřímo kontaktovat:

MyElement.parentNode.removeChild(myElement)

Metody pro prvky

Každý prvek má vlastnosti jako .innerHTML a .textContent , obsahuje HTML kód a tedy i samotný text. Následující příklad změní obsah prvku:

// Změňte HTML myElement.innerHTML = ` Nový obsah ( el.addEventListener("change", function (event) ( console.log(event.target.value) )) ))

Zabránění výchozím akcím

Chcete-li to provést, použijte metodu .preventDefault(), která blokuje standardní akce. Například zablokuje odeslání formuláře, pokud autorizace na straně klienta nebyla úspěšná:

MyForm.addEventListener("submit", funkce (událost) ( const name = this.querySelector("#name") if (name.value === "Kačer Donald") { alert("You gotta be kidding!") event.preventDefault() } }) !}

Metoda .stopPropagation() vám pomůže, pokud máte konkrétní obslužnou rutinu události přiřazenou k podřízenému prvku a druhou obslužnou rutinu události přiřazenou k nadřazené události pro stejnou událost.

Jak bylo uvedeno dříve, metoda .addEventListener() přebírá volitelný třetí argument ve formě konfiguračního objektu. Tento objekt musí obsahovat kteroukoli z následujících booleovských vlastností (všechny jsou ve výchozím nastavení nastaveny na false):

  • zachytit: událost bude připojena k tomuto prvku před jakýmkoli jiným prvkem níže v DOM;
  • jednou: událost lze přiřadit pouze jednou;
  • pasivní: event.preventDefault() bude ignorována (výjimka při chybě).

Nejběžnější vlastností je .capture a je tak běžná, že pro ni existuje zkratka: místo předávání v konfiguračním objektu stačí předat její hodnotu zde:

MyElement.addEventListener(typ, posluchač, pravda)

Obslužné rutiny se odstraňují pomocí metody .removeEventListener(), která přebírá dva argumenty: typ události a odkaz na obslužnou rutinu, která se má odstranit. Vlastnost Once lze například implementovat takto:

MyElement.addEventListener("změna", posluchač funkce (událost) ( console.log(event.type + " se spustilo na " + toto) this.removeEventListener("change", listener) ))

Dědictví

Řekněme, že máte prvek a chcete přidat obsluhu události pro všechny jeho potomky. Pak byste je museli procházet pomocí metody myForm.querySelectorAll("input"), jak je uvedeno výše. Můžete však jednoduše přidat prvky do formuláře a zkontrolovat jejich obsah pomocí event.target .

MyForm.addEventListener("change", function (event) ( const target = event.target if (target.matches("input")) ( console.log(target.value) ) ))

A ještě jedno plus tato metoda je, že handler bude automaticky připojen k novým podřízeným prvkům.

Animace

Nejjednodušší způsob, jak přidat animaci, je pomocí CSS s vlastností transition. Ale pro větší flexibilitu (například pro hry) se lépe hodí JavaScript.

Volání metody window.setTimeout() do konce animace není nejlepší nápad, protože vaše aplikace může zamrznout, zejména na mobilní zařízení. Pro uložení všech změn do dalšího překreslení je lepší použít window.requestAnimationFrame(). Bere funkci jako argument, který zase obdrží časové razítko:

Const start = window.performance.now() const Duration = 2000 window.requestAnimationFrame(funkce fadeIn (nyní)) ( const progress = now - start myElement.style.opacity = progress / trvání if (progress< duration) { window.requestAnimationFrame(fadeIn) } }

Tímto způsobem je dosaženo velmi hladké animace. Mark Brown ve svém článku pojednává o tomto tématu.

Psaní vlastní knihovny

Skutečnost, že v DOM musíte prvky neustále iterovat, abyste mohli provádět jakékoli operace s prvky, se může zdát docela zdlouhavá ve srovnání se syntaxí $(".foo").css((color: "red") jQuery. Ale proč nenapsat pár vlastních metod, které si tento úkol usnadní?

Const $ = funkce $ (selektor, kontext = dokument) ( prvky const = Array.from(context.querySelectorAll(selektor)) return ( prvky, html (newHtml) ( this.elements.forEach(element => ( element.innerHTML = newHtml )) return this ), css (newCss) ( this.elements.forEach(element => ( Object.assign(element.style, newCss) )) return this ), on (event, handler, options) ( this.elements .forEach(element => ( element.addEventListener(event, handler, options) )) return this ) ) )

Když otevřete jakýkoli dokument HTML, prohlížeč nejprve analyzuje jeho obsah a na základě této analýzy vytvoří objektový model dokumentu HTML, zkráceně DOM.

DOM se skládá z hierarchicky vnořených objektů nazývaných uzly. Každý uzel ve struktuře představuje umístění na HTML stránkuživel.

Pomocí DOM můžete komunikovat ( číst, měnit, mazat) s obsahem HTML dokumentů ze skriptů.

Níže je uveden kód pro HTML dokument a DOM, které by byly vytvořeny prohlížečem na základě tohoto kódu:

HTML DOM HTML DOM.

Ahoj všichni.

Všechny obdélníky zobrazené na obrázku jsou objekty (nebo uzly). Uzly různých typů jsou na obrázku označeny různými barvami.

Uzel Dokument je označen červeně. Jakýkoli přístup k DOM musí začínat přístupem k tomuto uzlu.

Elementární uzly jsou označeny zeleně. Pro každý prvek HTML na stránce prohlížeč vytvoří odpovídající uzel prvku.

Obsah prvků je uložen v textových uzlech. Textové uzly jsou v našem diagramu označeny modře.

Pro každého HTML atribut element je vytvořen atributový uzel. Uzel atributu je na diagramu označen růžově.

Poznámka: Pamatujte, že text je vždy uložen v textových uzlech a není vlastností prvku. Tito. Chcete-li získat přístup k obsahu prvku HTML, musíte získat přístup k jeho vlastnosti textového uzlu.

Vztahy mezi uzly

Uzly ve struktuře objektu jsou vzájemně propojeny. Existuje několik speciálních termínů pro popis vztahů mezi uzly:

Nadřazený uzel ( nadřazený uzel) - nadřazený uzel ve vztahu k danému objektu je uzel, do kterého je daný objekt vnořen. V našem diagramu ve vztahu k uzlům a

je rodič. Pro uzel je nadřazený uzel .

Sestupné uzly ( podřízený uzel) - podřízený uzel ve vztahu k dotyčnému objektu je uzel, který je vnořen do dotyčného objektu. V našem diagramu ve vztahu k uzlu a

Jsou to potomci. Pro uzel je dítě .

Sourozenecké uzly ( sourozenecký uzel) - uzly, které jsou na stejné úrovni vnoření vzhledem k jejich nadřazenému uzlu. V našem diagramu jsou sourozenecké uzly a ,

Nejvyšší uzel v DOM se nazývá kořen. V našem diagramu je to kořen (protože objekt dokumentu není součástí DOM).

V této lekci se podíváme na to, co je DOM, proč je potřeba a jak se vytváří.

Co je DOM?

Když prohlížeč požádá o stránku a obdrží svůj zdrojový kód HTML jako odpověď ze serveru, musí jej nejprve analyzovat. V procesu analýzy a analýzy HTML kódu prohlížeč na jeho základě vytvoří strom DOM.

Po dokončení této akce a řady dalších začne prohlížeč vykreslovat stránku. V tomto procesu už samozřejmě používá strom DOM, který vytvořil, a ne původní HTML kód.

DOM je objektový model dokumentu, který prohlížeč vytváří v paměti počítače na základě HTML kódu, který obdrží ze serveru.

Zjednodušeně řečeno, HTML kód je text stránky a DOM je sada souvisejících objektů vytvořených prohlížečem při analýze jejího textu.

V prohlížeči Chrome lze zdrojový kód stránky, kterou prohlížeč obdrží, zobrazit na kartě „Zdroj“ na panelu „Nástroje pro vývojáře webu“.


Chrome nemá nástroj, pomocí kterého byste si mohli prohlédnout strom DOM, který vytváří. Existuje však reprezentace tohoto stromu DOM ve formě HTML kódu, je k dispozici na kartě „Prvky“. Tato reprezentace DOM je samozřejmě mnohem pohodlnější pro práci webového vývojáře. Neexistuje tedy žádný nástroj, který by reprezentoval DOM jako stromovou strukturu.


Objekty v tomto modelu jsou tvořeny téměř ze všeho, co je v HTML (značky, textový obsah, komentáře atd.), včetně samotného dokumentu. Vztahy mezi těmito objekty v modelu jsou tvořeny na základě toho, jak jsou prvky HTML umístěny relativně vůči sobě v kódu.

V tomto případě lze DOM dokumentu po jeho vytvoření změnit. Když se změní DOM, prohlížeč téměř okamžitě překreslí obrázek stránky. Výsledkem je, že naše vykreslování stránky vždy odpovídá modelu DOM.

Pro čtení a změnu DOM programově nám prohlížeč poskytuje DOM API nebo jinými slovy programovací rozhraní. Jednoduše řečeno, DOM API je kolekce obrovského množství různých objektů, jejich vlastností a metod, které můžeme použít ke čtení a změně DOM.

Pro práci s DOM se ve většině případů používá JavaScript, protože... Dnes je to jediný programovací jazyk, ve kterém lze spouštět skripty v prohlížeči.

Proč potřebujeme DOM API? Potřebujeme to, abychom mohli pomocí JavaScriptu měnit stránku za chodu, tzn. aby to bylo dynamické a interaktivní.

DOM API nám (vývojářům) poskytuje obrovské množství metod, kterými můžeme na stránce vše měnit, ale i interagovat s uživatelem. Tito. toto softwarové rozhraní nám umožňuje vytvářet komplexní rozhraní, formuláře, zpracovávat uživatelské akce, přidávat a odebírat různé prvky na stránce, měnit jejich obsah, vlastnosti (atributy) a mnoho dalšího.

V dnešní době na webu prakticky neexistují stránky, jejichž scénáře by s DOM nefungovaly.

Z čeho se skládá HTML kód stránky?

Než přejdete ke studiu objektového modelu dokumentu, musíte si nejprve zapamatovat, jaký je zdrojový kód webové stránky (dokument HTML).

Zdrojový kód webové stránky se skládá ze značek, atributů, komentářů a textu. Tagy jsou základní syntaktická konstrukce HTML. Většina z nich je spárovaná. V tomto případě se jeden z nich otevírá a druhý zavírá. Jeden takový pár tagů tvoří HTML element. HTML prvky mohou mít Extra možnosti- atributy.

V dokumentu, aby se vytvořilo určité označení, jsou některé prvky umístěny uvnitř jiných. V důsledku toho může být dokument HTML reprezentován jako sada prvků HTML vnořených do sebe.

Jako příklad zvažte následující kód HTML:

Název stránky Název článku Sekce článku

Obsah článku

V tomto kódu je kořenovým prvkem html. Obsahuje prvky hlavy a těla. Element head obsahuje nadpis a tělo obsahuje h1 a div. Element div zase obsahuje h2 a p .

Nyní se podíváme na to, jak prohlížeč vytváří strom DOM založený na HTML kódu.

Jak se vytváří strom DOM dokumentu?

Jak již bylo popsáno výše, prohlížeč vytváří strom založený na prvcích HTML a dalších entitách zdrojový kód stránky. Při provádění tohoto procesu bere v úvahu vnořování prvků do sebe.

Výsledkem je, že prohlížeč používá výsledný strom DOM nejen při své práci, ale poskytuje nám také API pro pohodlná práce s ním přes JavaScript.

Při konstrukci DOM prohlížeč vytváří objekty (uzly stromu DOM) z prvků HTML, textu, komentářů a dalších entit tohoto jazyka.

Ve většině případů se webové vývojáře zajímají pouze o objekty (uzly) tvořené z prvků HTML.

Prohlížeč přitom nejen vytváří objekty z HTML prvků, ale také je mezi sebou propojuje určitými vazbami podle toho, jak se každý z nich v kódu týká toho druhého.

Prvky, které jsou přímo v nějakém prvku, jsou ve vztahu k němu děti. A pro každého z nich je rodičem. Všechny tyto prvky jsou navíc ve vztahu k sobě sourozenci (bratři).

Navíc v HTML má každý prvek vždy jednoho rodiče (prvek HTML, ve kterém se přímo nachází). V HTML nemůže mít prvek více rodičů. Jedinou výjimkou je prvek html. Nemá rodiče.

Chcete-li získat strom DOM tak, jak jej prohlížeč sestavuje, stačí „uspořádat“ všechny prvky v závislosti na jejich vzájemném vztahu.

Vytváření stromu DOM se provádí shora dolů.

V tomto případě je kořenem stromu DOM vždy samotný dokument (uzel dokumentu). Dále je strom sestaven v závislosti na struktuře HTML kódu.

Například kód HTML, na který jsme se podívali výše, by měl následující strom DOM:


Na samém vrcholu tohoto stromu je uzel dokumentu. Tento uzel spojený s html, je jeho potomkem. Vytvoří se uzel html html prvek(...). Uzly head(...) a body(...) mají rodičovský vztah s html. Ve vztahu k sobě jsou sourozenci, protože mít jednoho rodiče. Hlavní uzel je spojen s názvem (lt;title>...), je jeho potomkem. Uzly h1 a div jsou spojeny s body , což je jejich rodič. Uzel div je připojen k h2(...) a p(), jsou to jeho potomci.

Strom začíná, jak je uvedeno výše, objektem dokumentu (uzlem). Má zase jeden podřízený uzel tvořený prvkem html (...). Prvky hlava(...) a tělo(...) jsou v html a jsou tedy jeho potomky. Dále je hlavní uzel rodičem názvu (lt;title>...). Prvky h1 a div jsou vnořeny do těla, což znamená, že jsou jeho potomky. Div přímo obsahuje prvky h2 (...) a p (). To znamená, že uzel div pro každý z nich je rodič.

Takto snadno lze vytvořit strom DOM v prohlížeči na základě kódu HTML.

Proč potřebujete vědět, jak je strom DOM postaven? Za prvé je to pochopení prostředí, ve kterém chcete něco změnit. Za druhé, většina akcí při práci s DOM spočívá v hledání (výběru) potřebných prvků. Bez znalosti struktury stromu DOM a vazeb mezi uzly v něm bude poměrně obtížné najít konkrétní prvek.

Cvičení

Na základě stromu DOM zobrazeného na obrázku vytvořte HTML kód.


Hlavním nástrojem pro práci a dynamické změny na stránce je DOM (Document Object Model) - objektový model používaný pro XML/HTML dokumenty.

Podle modelu DOM je dokument hierarchií.
Každá značka HTML tvoří samostatný prvek uzlu, každý text tvoří prvek textu atd.

Jednoduše řečeno, DOM je reprezentace dokumentu jako stromu značek. Tento strom je tvořen vnořenou strukturou značek a textových fragmentů stránky, z nichž každý tvoří samostatný uzel.

Nejjednodušší DOM

Nejprve sestavíme strom DOM pro další dokument.

Název: Vynikající dokument

Vnější značka je , takže strom začíná růst odtud.

Uvnitř jsou dva uzly: a - stanou se podřízenými uzly .

Formulář značek uzly prvků(uzel prvku). Text předložen textové uzly(textový uzel). Oba jsou stejné uzly ve stromu DOM.

Složitější příklad

Podívejme se nyní na důležitější stránku:

O losech Pravda o losech.

  • Elk je mazané zvíře
  • .. A zákeřný
  • Kořenový prvek hierarchie je html. Má dva potomky. První je hlava, druhá je tělo. A tak dále, každá vnořená značka je potomkem výše uvedené značky:

    Na tomto obrázku modrá označuje prvky uzlu, černá označuje textové prvky.

    Strom je tvořen modrými uzlovými prvky - HTML tagy.

    A takto vypadá strom, pokud jej zobrazíte přímo na stránce HTML:

    Mimochodem, strom na tomto obrázku nebere v úvahu text sestávající pouze z mezer. Například takový textový uzel by měl následovat bezprostředně po . Zavolá se DOM, který takové "prázdné" uzly neobsahuje "normalizovaný".

    Podívejme se na trochu složitější dokument.

    Data dokumentu

    • Opatrně
    • Informace
    Vyrobeno v Rusku

    Horní značka je html, má dětskou hlavu a tělo a tak dále. Výsledkem je strom značek:

    Atributy

    V tomto příkladu mají uzly následující atributy: style , class , id . Obecně řečeno, atributy jsou také považovány za uzly v DOM, jejichž rodičem je prvek DOM, na kterém jsou specifikovány.

    Ve webovém programování se však do této džungle obvykle neponořují a atributy považují za pouhé vlastnosti uzlu DOM, které, jak uvidíme později, lze nastavit a změnit na žádost programátora.

    To je vlastně tajemství, ale DOCTYPE je také uzel DOM a nachází se ve stromu DOM vlevo od HTML (tato skutečnost je skryta na obrázku).

    P.S. Je to samozřejmě vtip o tajemství, ale ne každý o tom opravdu ví. Těžko si představit, kde by se takové znalosti mohly hodit...

    Normalizace v různých prohlížečích

    Při analýze HTML internet Explorer okamžitě vytvoří normalizované DOM, ve kterém se uzly nevytvářejí z prázdného textu.

    Firefox má jiný názor, z každého textového fragmentu vytváří prvek DOM.
    Ve Firefoxu tedy strom tohoto dokumentu vypadá takto:

    Na obrázku jsou pro stručnost textové uzly jednoduše označeny křížkem. tělo má 7 dětí místo 3.

    Opera se má také čím chlubit. Může přidat další prázdný prvek „jen ze sebe“.

    Chcete-li to zobrazit, otevřete dokument. Vrátí počet podřízených uzlů souboru document.body , včetně textových uzlů.

    Dostanu 3 pro IE, 7 pro Firefox a 8 (!?) pro Operu.

    V praxi tato nekompatibilita nevzniká velké problémy, ale musíte si to pamatovat. Rozdíl se může projevit například v případě výčtu uzlů stromu.

    Možnosti, které DOM dává

    Proč kromě krásných kreseb potřebujeme hierarchický DOM?

    Velmi jednoduché:

    Každý prvek DOM je objekt a poskytuje vlastnosti pro manipulaci s jeho obsahem, pro přístup k rodičům a dětem.

    Objekt dokumentu se používá pro manipulaci s DOM.
    Pomocí document můžete získat požadovaný prvek stromu a změnit jeho obsah.

    Tento kód například vezme první prvek s tagem ol, odebere postupně dva prvky seznamu a poté je přidá v opačném pořadí:

    Var ol = document.getElementsByTagName("ol") var hiter = ol.removeChild(ol.firstChild) var kovaren = ol.removeChild(ol.firstChild) ol.appendChild(kovaren) ol.appendChild(hiter)

    Pro ukázku, jak takový skript funguje, klikněte na text na stránce los

    Ve starých návodech a skriptech můžete vidět úpravu HTML kódu stránky přímo voláním document.write .

    V moderních skriptech se tato metoda téměř nepoužívá, případy jejího správného použití lze spočítat na jedné ruce.

    Vyhněte se document.write.. Kromě případů, kdy opravdu víte, co děláte (proč tedy čtete tutoriál - už jste guru)

    Podívejme se blíže na přístupové metody a vlastnosti prvků DOM.

    Přístupové prvky

    Všechny přístupy a úpravy DOM pocházejí z objektu dokumentu.

    Začněme na vrcholu stromu.

    document.documentElement

    Horní štítek. V případě správné HTML stránky to bude .

    dokument.tělo

    Tag, pokud je v dokumentu uveden (musí být).

    Následující příklad vytvoří po kliknutí na tlačítko textovou reprezentaci objektů document.documentElement a document.body. Samotný řetězec závisí na prohlížeči, i když objekty jsou všude stejné.

    function go() ( alert(document.documentElement) alert(document.body) )

    Typy prvků DOM

    Každý prvek v DOM má svůj typ. Jeho číslo je uloženo v atributu elem.nodeType

    Celkem je v DOM 12 typů prvků.

    Obvykle se používá pouze jeden: Node.ELEMENT_NODE, jehož číslo je 1. Prvky tohoto typu odpovídají značkám HTML.

    Někdy se hodí i typ Node.TEXT_NODE, který se rovná 3. Jedná se o textové prvky.

    Jiné typy se v programování javascriptu nepoužívají.

    Následující příklad po kliknutí na tlačítko vytiskne typy document.documentElement a poté typ posledního potomka uzlu document.body. Toto je textový uzel.

    function go() ( alert(document.documentElement.nodeType) alert(document.body.lastChild.nodeType) ) Text

    Příklad

    Takto by například vypadal dokument z výše uvedeného příkladu v prohlížeči, pokud by byl každý viditelný prvek obklopen rámečkem s číslem nodeType v pravém horním rohu.

    ...Data

    • Opatrně
    • Informace
    Vyrobeno v Rusku

    Zde jsou zobrazeny pouze prvky uvnitř těla, protože jsou jediné, které se zobrazují na stránce. U prvků typu 1 (značky) je odpovídající značka uvedena v závorce u textových prvků (typ 3) je pouze číslo.

    Dětské prvky
  • Všechny podřízené prvky, včetně textových, jsou v poli childNodes.

    Následující příklad prochází všemi potomky document.body .

    For(var i=0; i TĚLO

    styl

    Tato vlastnost řídí styl. Je to podobné jako nastavování stylu v CSS.

    Můžete například nastavit element.style.width:

    Zdrojový kód pro toto tlačítko:

    Jíst obecné pravidlo nahrazení - pokud má atribut CSS pomlčky, pak pro nastavení stylu je musíte nahradit velká písmena písmena

    Chcete-li například nastavit vlastnost z-index na 1000, musíte nastavit:

    Element.style.zIndex = 1000

    vnitřní HTML

    Kdysi byla tato vlastnost podporována pouze v IE. Nyní to podporují všechny moderní prohlížeče.

    Obsahuje veškerý HTML kód uvnitř uzlu a lze jej změnit.

    Vlastnost innerHTML se používá hlavně k dynamické změně obsahu stránky, například:

    Document.getElementById("footer").innerHTML = "Na shledanou!"

    InnerHTML je možná jednou z nejčastěji používaných vlastností prvku DOM.

    jméno třídy

    Tato vlastnost určuje třídu prvku. Je zcela podobný atributu html „class“.

    Elem.className = "nová třída"

    onclick, onkeypress, onfocus...

    A další vlastnosti začínající na „on...“ ukládají funkce obsluhy pro odpovídající události. Můžete například přiřadit obsluhu události onclick.

    Další informace o těchto vlastnostech a obslužných rutinách událostí naleznete v tématu