Úprava dokumentu

Modifikace DOM je klíčem k vytváření „živých“ stránek.

Zde uvidíme, jak vytvářet nové prvky „za běhu“ a upravovat stávající obsah stránky.

Příklad:zobrazit zprávu

Ukažme si to na příkladu. Na stránku přidáme zprávu, která bude vypadat lépe než alert .

Zde je návod, jak to bude vypadat:

<style>
.alert {
 padding: 15px;
 border: 1px solid #d6e9c6;
 border-radius: 4px;
 color: #3c763d;
 background-color: #dff0d8;
}
</style>

<div class="alert">
 <strong>Hi there!</strong> You've read an important message.
</div>

To byl příklad HTML. Nyní vytvoříme stejný div s JavaScriptem (za předpokladu, že styly jsou již v HTML/CSS).

Vytvoření prvku

Chcete-li vytvořit uzly DOM, existují dva způsoby:

document.createElement(tag)

Vytvoří nový uzel prvku s danou značkou:

let div = document.createElement('div');
document.createTextNode(text)

Vytvoří nový textový uzel s daným textem:

let textNode = document.createTextNode('Here I am');

Většinu času potřebujeme vytvořit uzly prvků, jako je div pro zprávu.

Vytvoření zprávy

Vytvoření div se zprávou trvá 3 kroky:

// 1. Create <div> element
let div = document.createElement('div');

// 2. Set its class to "alert"
div.className = "alert";

// 3. Fill it with the content
div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";

Vytvořili jsme prvek. Ale zatím je to pouze v proměnné s názvem div , ještě není na stránce. Takže to nevidíme.

Metody vkládání

Chcete-li vytvořit div se zobrazí, musíme jej vložit někam do document . Například do <body> prvek, na který se odkazuje document.body .

Existuje speciální metoda append za to:document.body.append(div) .

Zde je úplný kód:

<style>
.alert {
 padding: 15px;
 border: 1px solid #d6e9c6;
 border-radius: 4px;
 color: #3c763d;
 background-color: #dff0d8;
}
</style>

<script>
 let div = document.createElement('div');
 div.className = "alert";
 div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";

 document.body.append(div);
</script>

Zde jsme zavolali append na document.body , ale můžeme zavolat append metoda na jakýkoli jiný prvek, vložit do něj další prvek. Například můžeme přidat něco k <div> voláním div.append(anotherElement) .

Zde je více metod vkládání, které určují různá místa, kam vložit:

  • node.append(...nodes or strings) – připojit uzly nebo řetězce na konec z node ,
  • node.prepend(...nodes or strings) – vložte uzly nebo řetězce na začátek z node ,
  • node.before(...nodes or strings) – vložit uzly nebo řetězce před node ,
  • node.after(...nodes or strings) – vložit uzly nebo řetězce za node ,
  • node.replaceWith(...nodes or strings) –- nahrazuje node s danými uzly nebo řetězci.

Argumenty těchto metod jsou libovolný seznam uzlů DOM k vložení nebo textové řetězce (které se automaticky stanou textovými uzly).

Pojďme je vidět v akci.

Zde je příklad použití těchto metod k přidání položek do seznamu a textu před ním/za ním:

<ol id="ol">
 <li>0</li>
 <li>1</li>
 <li>2</li>
</ol>

<script>
 ol.before('before'); // insert string "before" before <ol>
 ol.after('after'); // insert string "after" after <ol>

 let liFirst = document.createElement('li');
 liFirst.innerHTML = 'prepend';
 ol.prepend(liFirst); // insert liFirst at the beginning of <ol>

 let liLast = document.createElement('li');
 liLast.innerHTML = 'append';
 ol.append(liLast); // insert liLast at the end of <ol>
</script>

Zde je vizuální obrázek toho, co metody dělají:

Takže konečný seznam bude:

before
<ol id="ol">
 <li>prepend</li>
 <li>0</li>
 <li>1</li>
 <li>2</li>
 <li>append</li>
</ol>
after

Jak již bylo řečeno, tyto metody mohou vložit více uzlů a částí textu do jednoho volání.

Zde je například vložen řetězec a prvek:

<div id="div"></div>
<script>
 div.before('<p>Hello</p>', document.createElement('hr'));
</script>

Poznámka:text je vložen „jako text“, nikoli „jako HTML“, se správným escapováním znaků, jako je < , > .

Takže konečný HTML je:

&lt;p&gt;Hello&lt;/p&gt;
<hr>
<div id="div"></div>

Jinými slovy, řetězce se vkládají bezpečným způsobem, například elem.textContent dělá to.

Tyto metody lze tedy použít pouze pro vkládání uzlů DOM nebo částí textu.

Ale co když bychom chtěli vložit řetězec HTML „jako html“, přičemž všechny značky a věci fungují stejným způsobem jako elem.innerHTML ano?

vložteAdjacentHTML/Text/Element

K tomu můžeme použít jinou, velmi všestrannou metodu:elem.insertAdjacentHTML(where, html) .

První parametr je kódové slovo, které určuje, kam se má vložit vzhledem k elem . Musí být jedna z následujících:

  • "beforebegin" – vložte html bezprostředně před elem ,
  • "afterbegin" – vložte html do elem , na začátku,
  • "beforeend" – vložte html do elem , na konci,
  • "afterend" – vložte html bezprostředně po elem .

Druhým parametrem je řetězec HTML, který se vkládá „jako HTML“.

Například:

<div id="div"></div>
<script>
 div.insertAdjacentHTML('beforebegin', '<p>Hello</p>');
 div.insertAdjacentHTML('afterend', '<p>Bye</p>');
</script>

…Vedlo by k:

<p>Hello</p>
<div id="div"></div>
<p>Bye</p>

Takto můžeme ke stránce připojit libovolný HTML.

Zde je obrázek variant vložení:

Snadno si můžeme všimnout podobnosti mezi tímto a předchozím obrázkem. Body vložení jsou ve skutečnosti stejné, ale tato metoda vloží HTML.

Metoda má dva bratry:

  • elem.insertAdjacentText(where, text) – stejná syntaxe, ale řetězec text se vkládá „jako text“ místo HTML,
  • elem.insertAdjacentElement(where, elem) – stejná syntaxe, ale vloží prvek.

Existují hlavně proto, aby byla syntaxe „jednotná“. V praxi pouze insertAdjacentHTML se používá většinu času. Protože pro prvky a text máme metody append/prepend/before/after – jsou kratší pro zápis a mohou vkládat uzly/části textu.

Zde je tedy alternativní varianta zobrazení zprávy:

<style>
.alert {
 padding: 15px;
 border: 1px solid #d6e9c6;
 border-radius: 4px;
 color: #3c763d;
 background-color: #dff0d8;
}
</style>

<script>
 document.body.insertAdjacentHTML("afterbegin", `<div class="alert">
 <strong>Hi there!</strong> You've read an important message.
 </div>`);
</script>

Odstranění uzlu

Chcete-li odebrat uzel, existuje metoda node.remove() .

Necháme naše sdělení po vteřině zmizet:

<style>
.alert {
 padding: 15px;
 border: 1px solid #d6e9c6;
 border-radius: 4px;
 color: #3c763d;
 background-color: #dff0d8;
}
</style>

<script>
 let div = document.createElement('div');
 div.className = "alert";
 div.innerHTML = "<strong>Hi there!</strong> You've read an important message.";

 document.body.append(div);
 setTimeout(() => div.remove(), 1000);
</script>

Poznámka:pokud se chceme přesunout prvek na jiné místo – není třeba jej odstraňovat ze starého.

Všechny metody vložení automaticky odeberou uzel ze starého místa.

Pojďme si například vyměnit prvky:

<div id="first">First</div>
<div id="second">Second</div>
<script>
 // no need to call remove
 second.after(first); // take #second and after it insert #first
</script>

Klonování uzlů:cloneNode

Jak vložit ještě jednu podobnou zprávu?

Mohli bychom vytvořit funkci a dát tam kód. Alternativním způsobem by však bylo klonování stávající div a upravte text v něm (je-li to potřeba).

Někdy, když máme velký prvek, může to být rychlejší a jednodušší.

  • Volání elem.cloneNode(true) vytvoří „hluboký“ klon prvku – se všemi atributy a dílčími prvky. Pokud zavoláme elem.cloneNode(false) , pak je klon vytvořen bez podřízených prvků.

Příklad zkopírování zprávy:

<style>
.alert {
 padding: 15px;
 border: 1px solid #d6e9c6;
 border-radius: 4px;
 color: #3c763d;
 background-color: #dff0d8;
}
</style>

<div class="alert" id="div">
 <strong>Hi there!</strong> You've read an important message.
</div>

<script>
 let div2 = div.cloneNode(true); // clone the message
 div2.querySelector('strong').innerHTML = 'Bye there!'; // change the clone

 div.after(div2); // show the clone after the existing div
</script>

DocumentFragment

DocumentFragment je speciální uzel DOM, který slouží jako obal pro předávání seznamů uzlů.

Můžeme k němu připojit další uzly, ale když ho někam vložíme, pak se místo něj vloží jeho obsah.

Například getListContent níže vygeneruje fragment s <li> položky, které jsou později vloženy do <ul> :

<ul id="ul"></ul>

<script>
function getListContent() {
 let fragment = new DocumentFragment();

 for(let i=1; i<=3; i++) {
 let li = document.createElement('li');
 li.append(i);
 fragment.append(li);
 }

 return fragment;
}

ul.append(getListContent()); // (*)
</script>

Všimněte si, prosím, na posledním řádku (*) přidáme DocumentFragment , ale „prolne“, takže výsledná struktura bude:

<ul>
 <li>1</li>
 <li>2</li>
 <li>3</li>
</ul>

DocumentFragment se explicitně používá zřídka. Proč se připojovat ke speciálnímu druhu uzlu, když místo toho můžeme vrátit pole uzlů? Přepsaný příklad:

<ul id="ul"></ul>

<script>
function getListContent() {
 let result = [];

 for(let i=1; i<=3; i++) {
 let li = document.createElement('li');
 li.append(i);
 result.push(li);
 }

 return result;
}

ul.append(...getListContent()); // append + "..." operator = friends!
</script>

Zmiňujeme DocumentFragment hlavně proto, že nad tím jsou nějaké koncepty, jako je prvek šablony, kterému se budeme věnovat mnohem později.

Staré metody vkládání/odebírání

Stará škola Tyto informace pomáhají porozumět starým skriptům, ale nejsou potřebné pro nový vývoj.

Existují také metody manipulace DOM ze „staré školy“, které existují z historických důvodů.

Tyto metody pocházejí opravdu z dávných dob. V dnešní době není důvod je používat, protože moderní metody, jako je append , prepend , before , after , remove , replaceWith , jsou flexibilnější.

Jediný důvod, proč zde tyto metody uvádíme, je ten, že je můžete najít v mnoha starých skriptech:

parentElem.appendChild(node)

Připojí node jako poslední potomek parentElem .

Následující příklad přidá nový <li> do konce <ol> :

<ol id="list">
 <li>0</li>
 <li>1</li>
 <li>2</li>
</ol>

<script>
 let newLi = document.createElement('li');
 newLi.innerHTML = 'Hello, world!';

 list.appendChild(newLi);
</script>
parentElem.insertBefore(node, nextSibling)

Vloží node před nextSibling do parentElem .

Následující kód vloží novou položku seznamu před druhý <li> :

<ol id="list">
 <li>0</li>
 <li>1</li>
 <li>2</li>
</ol>
<script>
 let newLi = document.createElement('li');
 newLi.innerHTML = 'Hello, world!';

 list.insertBefore(newLi, list.children[1]);
</script>

Chcete-li vložit newLi jako první prvek to můžeme udělat takto:

list.insertBefore(newLi, list.firstChild);
parentElem.replaceChild(node, oldChild)

Nahrazuje oldChild s node mezi dětmi parentElem .

parentElem.removeChild(node)

Odebere node od parentElem (za předpokladu node je jeho dítě).

Následující příklad odstraní první <li> od <ol> :

<ol id="list">
 <li>0</li>
 <li>1</li>
 <li>2</li>
</ol>

<script>
 let li = list.firstElementChild;
 list.removeChild(li);
</script>

Všechny tyto metody vracejí vložený/odebraný uzel. Jinými slovy parentElem.appendChild(node) vrátí node . Ale obvykle se vrácená hodnota nepoužívá, pouze spustíme metodu.

Něco o „document.write“

Existuje ještě jedna, velmi stará metoda, jak přidat něco na webovou stránku:document.write .

Syntaxe:

<p>Somewhere in the page...</p>
<script>
 document.write('<b>Hello from JS</b>');
</script>
<p>The end</p>

Volání na document.write(html) zapíše html na stránku „právě tady a teď“. html řetězec lze generovat dynamicky, takže je trochu flexibilní. Pomocí JavaScriptu můžeme vytvořit plnohodnotnou webovou stránku a napsat ji.

Metoda pochází z dob, kdy neexistoval DOM, žádné standardy... Opravdu staré časy. Stále žije, protože ho používají skripty.

V moderních skriptech to můžeme vidět jen zřídka, kvůli následujícímu důležitému omezení:

Volání na číslo document.write funguje pouze při načítání stránky.

Pokud jej zavoláme později, stávající obsah dokumentu se vymaže.

Například:

<p>After one second the contents of this page will be replaced...</p>
<script>
 // document.write after 1 second
 // that's after the page loaded, so it erases the existing content
 setTimeout(() => document.write('<b>...By this.</b>'), 1000);
</script>

Na rozdíl od jiných metod DOM, které jsme probrali výše, je tedy ve fázi „po načtení“ poněkud nepoužitelný.

To je nevýhoda.

Existuje také výhoda. Technicky vzato, když document.write je volána, když prohlížeč čte (“analyzuje”) příchozí HTML a něco zapisuje, prohlížeč to spotřebovává, jako by to bylo původně v textu HTML.

Funguje to tedy neuvěřitelně rychle, protože nedochází k žádné úpravě DOM zapojený. Zapisuje přímo do textu stránky, zatímco DOM ještě není vytvořen.

Pokud tedy potřebujeme do HTML dynamicky přidat hodně textu a jsme ve fázi načítání stránky a na rychlosti záleží, může to pomoci. Ale v praxi se tyto požadavky jen zřídka setkávají. A obvykle můžeme tuto metodu vidět ve skriptech jen proto, že jsou staré.

Shrnutí

  • Metody vytváření nových uzlů:

    • document.createElement(tag) – vytvoří prvek s danou značkou,
    • document.createTextNode(value) – vytvoří textový uzel (používá se zřídka),
    • elem.cloneNode(deep) – klonuje prvek, pokud deep==true pak se všemi potomky.
  • Vkládání a vyjímání:

    • node.append(...nodes or strings) – vložte do node , na konci,
    • node.prepend(...nodes or strings) – vložte do node , na začátku,
    • node.before(...nodes or strings) – vložte přímo před node ,
    • node.after(...nodes or strings) – vložte hned za node ,
    • node.replaceWith(...nodes or strings) – nahraďte node .
    • node.remove() – odeberte node .

    Textové řetězce se vkládají „jako text“.

  • Existují také metody „staré školy“:

    • parent.appendChild(node)
    • parent.insertBefore(node, nextSibling)
    • parent.removeChild(node)
    • parent.replaceChild(newElem, node)

    Všechny tyto metody vrátí node .

  • Dané nějaké HTML v html , elem.insertAdjacentHTML(where, html) vloží jej v závislosti na hodnotě where :

    • "beforebegin" – vložte html těsně před elem ,
    • "afterbegin" – vložte html do elem , na začátku,
    • "beforeend" – vložte html do elem , na konci,
    • "afterend" – vložte html hned po elem .

    Také existují podobné metody, elem.insertAdjacentText a elem.insertAdjacentElement , které vkládají textové řetězce a prvky, ale používají se zřídka.

  • Chcete-li ke stránce přidat HTML před dokončením načítání:

    • document.write(html)

    Po načtení stránky takové volání dokument vymaže. Většinou se vyskytuje ve starých skriptech.


No