Godzina 1: DOM (obiektowy model dokumentu) - strona jako drzewo obiektów
Godzina 2: znajdujemy element na stronie
Godzina 3: zmieniamy tekst i wygląd elementu
Godzina 4: podmieniamy atrybut - src, class
Godzina 5 (dziś): dodajemy nowy element na stronę
Godzina 6: powtórka - łączymy wyszukiwanie, zmianę i tworzenie
Rozgrzewka · 3 minuty
Rozgrzewka: atrybuty z poprzedniej lekcji
Co robi setAttribute("src", "picture2.jpg") wywołane na elemencie <img>?
Jak odczytacie wartość atrybutu src metodą getAttribute?
Jak zmienicie klasę elementu poleceniem setAttribute?
Część 1 · Tworzymy element
createElement: nowy element, jeszcze poza drzewem
Do tej pory pracowaliście na elementach, które już były na stronie. document.createElement("li") tworzy zupełnie nowy element - jak wyjęcie nowego klocka z pudełka. Macie go w rękach, ale nie jest jeszcze wpięty w żadną konstrukcję: nie widać go na stronie, dopóki go gdzieś nie dołączycie.
const newItem = document.createElement("li");
MDN, Web/API/Document/createElement: „The createElement() method of the Document interface creates a new HTMLElement that has the specified localName.” - „Metoda createElement() interfejsu Document tworzy nowy obiekt HTMLElement o podanej nazwie localName.” (tłum. własne)
Część 2 · Dołączamy element
appendChild: dołączamy węzeł do rodzica
Sam createElement nie wystarczy - element trzeba jeszcze dołączyć do drzewa. list.appendChild(newItem) dołącza newItem jako ostatnie dziecko elementu list, tak jak dołączenie nowego wagonu na koniec pociągu. Dopiero po tym element pojawia się na stronie.
list.appendChild(newItem);
MDN, Web/API/Node/appendChild: „The appendChild() method of the Node interface adds a node to the end of the list of children of a specified parent node.” - „Metoda appendChild() interfejsu Node dodaje węzeł na koniec listy dzieci podanego węzła nadrzędnego.” (tłum. własne)
Część 3 · Wpisujemy tekst
textContent: co ma być widoczne w środku
Nowy element z createElement jest pusty w środku - to sam znacznik, bez treści. newItem.textContent = "Kupić mleko" wpisuje tekst do wnętrza elementu. Ten sam zapis znacie już z lekcji o zmianie treści (temat 3/6) - tam zmieniał tekst istniejącego elementu, tu ustawia tekst elementu, który dopiero co powstał.
Kolejność ma znaczenie tylko o tyle, że newItem musi już istnieć - samą kolejność textContent i appendChild możecie odwrócić, efekt końcowy jest taki sam.
MDN, Web/API/Node/textContent: „The textContent property of the Node interface represents the text content of the node and its descendants.” - „Właściwość textContent interfejsu Node reprezentuje zawartość tekstową węzła i jego potomków.” (tłum. własne)
Część 4 · Usuwamy element
remove(): odcinamy węzeł z drzewa
Metoda remove() wywołana na elemencie odcina go z drzewa DOM - jak odcięcie gałęzi z drzewa. Element znika ze strony. list.lastElementChild to ostatnie dziecko elementu list - w ten sposób znajdziecie ostatni element listy bez pamiętania jego id.
list.lastElementChild.remove();
MDN, Web/API/Element/remove: „The Element.remove() method removes the element from its parent node. If it has no parent node, calling remove() does nothing.” - „Metoda Element.remove() usuwa element z jego węzła nadrzędnego. Jeśli element nie ma węzła nadrzędnego, wywołanie remove() nic nie robi.” (tłum. własne)
function addItem() {
const list = document.getElementById("tasks");
const newItem = document.createElement("li");
newItem.textContent = "Nowe zadanie";
list.appendChild(newItem);
}
function removeLast() {
const list = document.getElementById("tasks");
list.lastElementChild.remove();
}
Kod zgodny ze składnią createElement/appendChild/remove (slajdy 3-6)
Egzamin EE.09
Tak pytają na egzaminie o DOM
W bankach zadań CKE nie ma na razie pytania wprost o createElement, appendChild ani remove(). Pisemne pytania o DOM (obiektowy model dokumentu) dotyczą częściej wyszukiwania elementu i zmiany jego treści - getElementById i innerHTML(tematy 2/6 i 3/6, lekcje 21 i 22).
Tworzenie i usuwanie elementów wraca za to w części praktycznej egzaminu - i w projektach na kolejnych lekcjach (gra, blog), gdzie strona sama dokłada elementy na podstawie danych.
Ćwiczenie przy komputerze · 20 minut
Ćwiczenie: dodajemy i usuwamy zadanie z listy
Otwórz page.html z poprzednich lekcji. Dodaj <ul id="tasks"> z jednym elementem <li> w środku i dwa przyciski: „Dodaj zadanie” i „Usuń ostatnie”.
W script.js napisz funkcję addItem(): pobierz listę po id, utwórz nowy <li> przez createElement, ustaw mu tekst przez textContent i dołącz do listy przez appendChild.
Napisz funkcję removeLast(): pobierz listę po id i wywołaj remove() na jej ostatnim dziecku (lastElementChild).
Sprawdź w przeglądarce: otwórz page.html, kliknij kilka razy „Dodaj zadanie”, potem „Usuń ostatnie” - lista ma rosnąć i się skracać.
Dla chętnych: zapisz zmiany w swoim repozytorium - commit „Dodaje tworzenie i usuwanie elementu listy”.
Czy element utworzony przez document.createElement("li") jest od razu widoczny na stronie?
Jakiej metody użyjecie, żeby dołączyć nowo utworzony element jako ostatnie dziecko istniejącego elementu?
Co się stanie, jeśli wywołacie remove() na elemencie, który nie ma rodzica (nie jest w drzewie)?
To tyle na dziś - kolejny temat: powtórka całego tematu DOM.
Poza szkołą
A jak to wygląda w produkcji?
Na lekcji
W produkcji
Status
createElement + appendChild ręcznie dla każdego elementu
Frameworki (React, Vue) budują drzewo z szablonu i danych, wywołania podobne do createElement/appendChild dzieją się w tle
zastępowane
Dodawanie elementów po jednym, w pętli
document.createDocumentFragment() - zbiera wiele nowych elementów naraz i dołącza je jednym appendChild, żeby przeglądarka nie przerysowywała strony przy każdym dodaniu (MDN zastrzega: bywa wolniejsze).
nadal w użyciu
list.lastElementChild.remove()
Biblioteki renderujące same usuwają węzeł, gdy odpowiadająca mu pozycja znika z danych (np. z tablicy)
zastępowane
Ciekawostka z MDN: document.createDocumentFragment() tworzy pojemnik w pamięci, do którego można dołączyć wiele nowych elementów, zanim jakikolwiek z nich trafi na stronę. Gdy taki fragment dołączycie do dokumentu przez appendChild, do drzewa DOM trafiają tylko jego dzieci - sam fragment zostaje pusty.
definicje metod - slajdy 3, 4, 6 (MDN) · zastrzeżenie: developer.mozilla.org/en-US/docs/Web/API/DocumentFragment („using a DocumentFragment is slower than appending to the document in a loop”, tłum. własne: „użycie DocumentFragment bywa wolniejsze niż dodawanie do dokumentu w pętli”)