Het Document Object Model
BeginnerLes 5 van 9 in Cursus JavaScript programmeren: DOM, events, asynchrone code en modules
Wat je leert
- Leg uit wat het Document Object Model is, hoe de browser het opbouwt uit HTML en hoe de knooppunten zich tot elkaar verhouden, zodat je je weg kunt vinden op elke pagina.
- Beschrijf het DOM als een boom van knooppuntenLeg uit wat het DOM is, hoe de browser het opbouwt uit HTML, welke soorten knooppunten het bevat en hoe het verschilt van de HTML-broncode.
- Navigeer van een element naar de ouder, de kinderen en de elementen met dezelfde ouderNavigeer vanaf een willekeurig element door de boom naar verwante knooppunten, kies tussen eigenschappen die tekstknooppunten meenemen en eigenschappen die alleen elementen teruggeven, en zoek de dichtstbijzijnde passende voorouder.
- Beschrijf het DOM als een boom van knooppunten
- Vind met CSS-selectors precies de elementen die een script nodig heeft, handel ontbrekende elementen af en werk met collecties van overeenkomende elementen.
- Selecteer één elementZoek één element met querySelector of getElementById, zoek binnen een deel van de pagina en handel af dat er geen overeenkomst is.
- Selecteer meerdere elementen en werk met de resultatenSelecteer elk overeenkomend element, doorloop de resultaten, converteer ze zo nodig naar een array en weet wanneer een collectie zichzelf bijwerkt.
- Selecteer één element
- Werk de tekst van elementen bij en de attributen en eigenschappen die ze aansturen, kies de veilige methode als inhoud van gebruikers of uit gegevens komt en bewaar extra gegevens op elementen.
- Wijzig de tekst en HTML binnen een elementLees en vervang de inhoud van een element met textContent, innerText en innerHTML en bescherm pagina's tegen geïnjecteerde code.
- Lees attributen en eigenschappen en stel ze inWerk met attributen via getAttribute en setAttribute en met de bijbehorende elementeigenschappen, en ga om met booleaanse attributen en verschillen tussen attributen en eigenschappen.
- Sla gegevens op in elementen en lees formuliervelden uitBewaar extra informatie op elementen met data-attributen en lees de actuele waarde van formuliervelden uit en stel die in.
- Wijzig de tekst en HTML binnen een element
- Schakel CSS-klassen, stel inlinestijlen in wanneer een waarde wordt berekend, lees de stijlen die de browser toepast en toon of verberg delen van een pagina.
- Voeg CSS-klassen toe, verwijder ze en schakel ze aan of uitWijzig het uiterlijk van een element door klassen te schakelen met classList en houd de vormgevingsregels in het stijlblad.
- Stel inlinestijlen in en lees berekende stijlen uitStel inlinestijlen via de eigenschap style in wanneer een waarde tijdens de uitvoering wordt berekend, verwijder ze weer en lees de stijlen uit die de browser daadwerkelijk toepast.
- Toon en verberg delen van een paginaVerberg en toon elementen met het attribuut hidden of een klasse, kies tussen de manieren waarop CSS iets onzichtbaar kan maken en houd de toestand duidelijk voor gebruikers van schermlezers.
- Voeg CSS-klassen toe, verwijder ze en schakel ze aan of uit
- Bouw nieuwe elementen in JavaScript, zet ze precies op de juiste plaats en verwijder, vervang of kopieer elementen, zodat de pagina verandert zonder opnieuw te laden.
- Maak nieuwe elementen en voeg ze inMaak elementen met createElement, vul ze met tekst en attributen en voeg ze in aan het einde, aan het begin of naast een ander element.
- Verwijder, vervang en kopieer elementenHaal elementen van de pagina, maak een container leeg, vervang het ene element door het andere en maak kopieën met cloneNode.
- Maak nieuwe elementen en voeg ze in
- Zet arrays met gegevens om in lijsten en tabellen op de pagina, bouw veel items efficiënt op en werk de pagina bij wanneer de gegevens veranderen.
- Bouw lijstitems en tabelrijen op vanuit een arrayZet een array van objecten met textContent om in lijstitems of tabelrijen, toon passende uitvoer bij lege lijsten en ontbrekende waarden en koppel elk element aan de bijbehorende gegevens.
- Bouw veel items efficiënt op met fragmenten en templatesVoeg veel nieuwe elementen in één stap in met een DocumentFragment of één append-aanroep en hergebruik opmaak die in een HTML-template-element is geschreven.
- Werk de pagina bij wanneer de gegevens veranderenHoud de gegevens als enige leidende gegevensbron, render na elke wijziging opnieuw vanuit die gegevens en toon gefilterde, gesorteerde en samenvattende weergaven zonder de oorspronkelijke gegevens te verliezen.
- Bouw lijstitems en tabelrijen op vanuit een array
Document Object Model: uitleg
1Lees de pagina als een boom
De browser zet HTML om in objecten die JavaScript kan lezen en wijzigen. Die objecten vormen een boom. Om een pagina-element te vinden, moet je dus ook begrijpen waar het tussen de andere knooppunten staat. Begin met de bekende tags te koppelen aan de objecten in de browser. Volg daarna de relaties tussen ouders, kinderen en knooppunten met dezelfde ouder en let op de tekstknooppunten die uit spaties en regeleinden ontstaan. Met DevTools kun je deze boom bekijken terwijl je code die wijzigt.
1.1 HTML wordt een boom van objecten
Het Document Object Model, of DOM, is de actuele boom van paginaobjecten in de browser. JavaScript leest en wijzigt deze objecten om de pagina bij te werken zonder opnieuw te laden. De browser biedt de DOM-API aan; JavaScript is de taal waarmee je die aanroept.
Begin bij het document
document is het toegangspunt. document.documentElement verwijst naar <html>, document.head naar <head> en document.body naar <body>. Het browsertabblad wordt vertegenwoordigd door window, waarvan de eigenschap document naar dit document verwijst.
Elk onderdeel in de boom is een knooppunt. Elementen vertegenwoordigen tags; tekstknooppunten bevatten tekens; commentaarknooppunten bevatten HTML-commentaar; het documentknooppunt staat boven de elementen van de pagina. Hun nodeType-waarden zijn respectievelijk 1, 3, 8 en 9. Elk element is een knooppunt, maar tekst en commentaar zijn geen elementen.
Lees de familierelaties
<ul id="menu"><li>Home</li><li>About</li></ul>
De lijst is de ouder van twee itemelementen met dezelfde ouder. Elk item is een kind van de lijst. Het eerste item heeft een tekstknooppunt als kind met de inhoud “Home”. De lijst is een voorouder van dat tekstknooppunt en de tekst is een nakomeling van de lijst. Deze relaties beschrijven de nesting, niet de posities op het scherm.
Spaties en regeleinden tussen tags worden meestal tekstknooppunten met witruimte. Een ingesprongen lijst kan daardoor twee kindelementen hebben, maar meer dan twee kindknooppunten. children en firstElementChild geven alleen elementen terug; childNodes en firstChild nemen ook tekst en commentaar mee.
Vergelijk de boom met de broncode
Bij het ontleden wordt opmaak omgezet in de boom. Daarbij kan de opmaak worden aangevuld of hersteld. Rijen die rechtstreeks binnen een <table> zijn geschreven, krijgen een <tbody> als ouder. Ontbrekende elementen <html>, <head> of <body> kunnen ook worden toegevoegd. Selecteer vanuit de daadwerkelijke boom, inclusief deze door de parser toegevoegde elementen.
Wijzigingen door scripts hebben invloed op het actuele DOM van de browser, niet op het HTML-bestand op de server. “Paginabron bekijken” toont de oorspronkelijke HTML, terwijl Elements in DevTools de actuele boom toont. Opnieuw laden bouwt een nieuw DOM op; een wijziging alleen slaat de achterliggende gegevens niet op.
Inspecteer een object
Klik met de rechtermuisknop op een element en kies “Inspecteren”. Voer $0 in de console in om naar dat geselecteerde element te verwijzen. console.log($0) toont het als opmaak; console.dir($0) toont de eigenschappen. Klap een ingesprongen lijst uit om de witruimteknooppunten naast de itemelementen te zien.
Belangrijkste punten
- Het DOM is een boom die de browser aanbiedt en die JavaScript kan lezen en wijzigen.
- Elementen, tekst, commentaar en het document zijn verschillende soorten knooppunten.
- Door witruimte en door de parser toegevoegde elementen kan het DOM verschillen van de geschreven HTML.
- Inspecteer de actuele boom in DevTools; een wijziging in het DOM herschrijft de HTML op de server niet.
1.2 Volg ouders, kinderen en knooppunten met dezelfde ouder
Met boomeigenschappen kan een script vanaf een element dat het al heeft nabije inhoud bereiken. Kies of dat pad tekst en commentaar moet meenemen of alleen elementen.
Kies knooppunten of elementen
Knooppunteigenschappen zijn onder meer parentNode, childNodes, firstChild, lastChild, previousSibling en nextSibling. De bijbehorende elementvarianten zijn parentElement, children, firstElementChild, lastElementChild, previousElementSibling en nextElementSibling. children is een HTMLCollection; childNodes is een NodeList.
<ul id="tasks">
<li>Buy milk</li>
<li>Call Sam</li>
</ul>
Hier is tasks.childNodes.length gelijk aan 5: twee elementen en drie stukken witruimte. tasks.children.length is gelijk aan 2. tasks.firstChild is tekst met witruimte, terwijl tasks.firstElementChild.textContent gelijk is aan “Buy milk”. Indexen beginnen bij 0, dus tasks.children[1] is het tweede item.
Volg een kort pad
const tasks = document.querySelector("#tasks");
const first = tasks.firstElementChild;
const second = first.nextElementSibling;
console.log(second.textContent);
console.log(second.parentElement === tasks);
De uitvoer is “Call Sam”, gevolgd door true. tasks.lastElementChild bereikt rechtstreeks hetzelfde item, net als tasks.children[tasks.children.length - 1].
Handel een ontbrekend verwant knooppunt af
De nextElementSibling van het laatste item is null. Een element zonder kindelementen heeft firstElementChild === null en een lege children-collectie. De parentNode van het HTML-hoofdelement is het document, maar de parentElement ervan is null.
Een eigenschap van null uitlezen veroorzaakt een TypeError. Controleer eerst of gebruik second.nextElementSibling?.textContent, dat undefined geeft als er geen volgend element bestaat.
Zoek een omhullend item
closest(selector) controleert het huidige element en daarna de voorouders en geeft de dichtstbijzijnde overeenkomst terug, of null. Een knop binnen <li class="task" data-id="7"> kan button.closest(".task") gebruiken; de dataset.id van het gevonden item is “7”. matches(selector) toetst daarentegen alleen het huidige element en geeft een booleaanse waarde terug.
Lange paden zoals el.parentElement.parentElement.nextElementSibling zijn afhankelijk van de precieze nesting. Een toegevoegd omhullend element verandert hun betekenis. Gebruik selectors voor benoemde delen, korte navigatie voor stabiele relaties en closest() voor een omhullend item.
Belangrijkste punten
- Gebruik navigatie met alleen elementen wanneer witruimte en commentaar moeten worden overgeslagen.
- Collecties beginnen bij index 0; hun lengte is een aantal, niet de laatste index.
- Een ontbrekend verwant knooppunt is null; controleer voordat je er iets uit leest.
- closest() controleert het element zelf en daarna de voorouders.
- matches() toetst het huidige element zonder door de boom te navigeren.
2Vind pagina-elementen
Een wijziging in het DOM begint met een referentie naar het juiste element. Met CSS-selectors kun je de hele pagina of slechts één container doorzoeken, terwijl je met collectiemethoden met meerdere resultaten kunt werken. De retourwaarde is van belang: de ene zoekopdracht kan een element of null opleveren, een andere geeft altijd een collectie. Je moet ook weten wanneer het script wordt uitgevoerd en of een opgeslagen collectie verandert wanneer de pagina verandert, omdat beide bepalen wat je code vindt.
2.1 Zoek één element en controleer het resultaat
Een selector zet een beschrijving van een element om in een objectreferentie. Begin met de kleinste zoekopdracht die het gewenste element aanwijst en controleer daarna of het element is gevonden voordat je het wijzigt.
Zoek met een CSS-selector of een id
document.querySelector(selector) geeft het eerste overeenkomende element in documentvolgorde terug. De methode accepteert bekende CSS-selectors: "h1", ".price", "#cart", "nav a" of 'input[type="email"]'. Als niets overeenkomt, geeft de methode null terug.
document.getElementById("cart") zoekt rechtstreeks naar een id. Het argument is alleen de id. getElementById("#cart") zoekt naar een id die daadwerkelijk het hekje bevat, terwijl querySelector("cart") naar een tag <cart> zoekt. Gebruik querySelector("#cart") voor de id-selector.
Id's moeten uniek zijn. Als gekopieerde opmaak twee elementen dezelfde id geeft, geven deze zoekopdrachten het eerste element in documentvolgorde terug. Herstel de dubbele opmaak in plaats van te verwachten dat een zoekopdracht op id de tweede kopie bereikt.
Zoek binnen een container
Stel dat meerdere kaarten een element met de klasse name hebben. Selecteer eerst de profielkaart en doorzoek daarna de nakomelingen:
const card = document.querySelector("#profile");
if (card) {
const name = card.querySelector(".name");
if (name) name.textContent = "Maya";
}
De zoekopdracht binnen de container blijft beperkt tot de profielkaart, zodat een eerdere .name elders niet stoort. De container zelf is geen kandidaat in zijn eigen querySelector()-zoekopdracht. Gewone elementen ondersteunen deze methode, maar getElementById() hoort bij document.
Onderscheid geen overeenkomst van een ongeldige selector
Een geldige zoekopdracht zonder overeenkomst geeft null. Als je null.textContent probeert in te stellen, ontstaat een TypeError. Controleer dus of optionele inhoud bestaat:
const banner = document.querySelector(".banner");
if (banner) banner.textContent = "Sale ends Friday";
Een ongeldige CSS-selector veroorzaakt een SyntaxError voordat er een resultaat kan zijn. Voor <p id="1st"> is querySelector("#1st") ongeldig omdat het cijfer in die CSS-id-selector moet worden ge-escaped. getElementById("1st") gebruikt een letterlijke id en werkt direct.
Voer de code uit nadat de benodigde opmaak bestaat
Een klassiek extern script in <head> wordt uitgevoerd voordat de browser de body heeft ontleed. Een zoekopdracht naar een latere alinea geeft daarom null terug, ook als de HTML die alinea bevat. Gebruik <script src="app.js" defer></script> om de code na het ontleden uit te voeren, gebruik een modulescript of plaats het script vlak voor </body>. Modulescripts worden standaard uitgesteld. Het attribuut defer heeft geen effect op een klassiek inlinescript.
Voor een HTML-pagina die begint met <!DOCTYPE html> zijn id- en klasseselectors hoofdlettergevoelig: .Price vindt class="price" niet. HTML-tagselectors zijn niet hoofdlettergevoelig, dus "LI" en "li" komen beide overeen met lijstitems. Als een zoekopdracht mislukt, controleer dan de spelling, de selectorsyntaxis, de zoekcontainer en het uitvoeringstijdstip van het script.
Belangrijkste punten
- querySelector() geeft de eerste overeenkomst of null terug.
- getElementById() verwacht alleen een id; querySelector() verwacht CSS-selectorsyntaxis.
- Doorzoek de nakomelingen van een container wanneer een klasse in meerdere delen van de pagina voorkomt.
- Een ontbrekende overeenkomst geeft null terug; ongeldige selectorsyntaxis veroorzaakt een fout.
- Voer DOM-code uit nadat de bijbehorende opmaak is ontleed.
- Houd id's uniek en let op hoofdletters en kleine letters in id- en klasseselectors.
2.2 Werk met collecties van overeenkomende elementen
Gebruik querySelectorAll() wanneer dezelfde bewerking op meerdere elementen moet worden toegepast. Het resultaat is een collectie, dus je moet bepalen hoe je die doorloopt en of je een momentopname of een dynamisch bijgewerkte weergave nodig hebt.
Lees en doorloop een NodeList
document.querySelectorAll(".note") geeft een NodeList met overeenkomende elementen in documentvolgorde terug. Zonder overeenkomsten krijg je een lege NodeList met lengte 0. De collectie zelf is nog steeds een truthy-waarde; if (notes) vertelt je niet of die elementen bevat. Controleer notes.length.
Een NodeList ondersteunt indexen, length, forEach() en for...of, maar is geen array en heeft geen map(), filter() of reduce(). Converteer de NodeList wanneer je die methoden nodig hebt:
const weights = Array.from(document.querySelectorAll(".weight"))
.map(el => Number(el.textContent));
const total = weights.reduce((sum, weight) => sum + weight, 0);
Voor elementen met “4.5”, “12” en “3.25” is de array [4.5, 12, 3.25] en het totaal 19,75 kg. De conversie naar getallen is belangrijk omdat de tekstwaarden strings zijn.
Een collectie is geen gecombineerd element. Als je notes.textContent instelt, wijzig je geen enkele notitie, en notes.classList.add("saved") veroorzaakt een fout omdat de NodeList geen classList heeft. Pas de wijziging op elk element toe:
const notes = document.querySelectorAll(".note");
notes.forEach(note => note.classList.add("saved"));
Vergelijk statische en dynamisch bijgewerkte resultaten
De NodeList van querySelectorAll() is statisch: welke elementen erbij horen, ligt vast wanneer de zoekopdracht wordt uitgevoerd. De elementen waarnaar de lijst verwijst, zijn nog steeds de daadwerkelijke objecten, zodat hun tekst of klassen kunnen veranderen.
getElementsByClassName("note") en getElementsByTagName("li") geven een dynamisch bijgewerkte HTMLCollection terug. Ook children wordt dynamisch bijgewerkt. Deze collecties werken bij welke elementen erbij horen wanneer het DOM verandert. Ze ondersteunen indexen en for...of, maar geen forEach().
Bewaar in een lijst met drie .item-elementen zowel list.getElementsByClassName("item") als list.querySelectorAll(".item"). Voeg een vierde overeenkomend element toe. De dynamisch bijgewerkte collectie heeft nu lengte 4; de momentopname heeft nog steeds lengte 3.
Voorkom de valkuil van een krimpende collectie in een lus
Stel dat vier elementen behoren tot een dynamisch bijgewerkte collectie met de naam live:
for (let i = 0; i < live.length; i++) {
live[i].classList.remove("item");
}
Als de eerste klasse wordt verwijderd, verdwijnt dat element uit de collectie. Het volgende element schuift op naar index 0, maar de lus gaat verder naar index 1 en slaat het over. Slechts twee van de vier verliezen de klasse. Doorloop Array.from(live) of een momentopname van querySelectorAll() wanneer je verandert welke elementen bij de collectie horen.
Controleer spaties in selectors
.task.done betekent één element met beide klassen. .task .done betekent een .done-nakomeling binnen een .task. Tel voor <li class="task done"> voltooide items met document.querySelectorAll(".task.done").length. Een komma combineert selectors: "h2, h3" geeft overeenkomsten in documentvolgorde terug, niet eerst alle koppen van het ene type en daarna die van het andere.
Belangrijkste punten
- Doorloop de leden van een collectie om hun inhoud of klassen te wijzigen.
- querySelectorAll() geeft een statische NodeList terug; een leeg resultaat heeft lengte 0.
- Converteer collecties met Array.from() of spreadsyntaxis voordat je methoden gebruikt die alleen voor arrays beschikbaar zijn.
- Bij dynamisch bijgewerkte collecties verandert welke elementen erbij horen als overeenkomende elementen veranderen.
- Maak een momentopname voordat je een lus gebruikt die leden uit een dynamisch bijgewerkte collectie verwijdert.
- Een spatie in een selector verandert de relatie waarnaar wordt gezocht.
3Werk inhoud en elementgegevens bij
Een element bevat verschillende soorten informatie: zichtbare tekst, HTML-structuur, attributen en JavaScript-eigenschappen. Door de juiste te kiezen, kun je een label bijwerken, een link wijzigen, een veld uitlezen of een weergegeven item aan de bijbehorende gegevens koppelen. Dezelfde tekst kan worden behandeld als gewone tekens of als HTML worden ontleed, met heel verschillende resultaten. Let goed op deze verschillen, zodat wijzigingen de bedoelde inhoud tonen en externe tekst veilig blijft.
3.1 Kies tekst of HTML om inhoud bij te werken
Tekst en HTML zijn verschillende soorten invoer. Platte tekst moet als tekens verschijnen; HTML beschrijft elementen die de browser moet opbouwen. De keuze heeft gevolgen voor zowel de paginastructuur als de mogelijkheid dat externe tekst ongewenste code uitvoert.
Lees en vervang tekst
Voor <p id="msg">Total: <strong>3</strong> items</p> is msg.textContent gelijk aan “Total: 3 items”. De eigenschap voegt tekst van de nakomelingen van het element samen zonder hun tags mee te nemen en bevat ook tekst die door CSS is verborgen.
Als je textContent instelt, vervang je alle kinderen door een tekstknooppunt. Na msg.textContent = "Cart is empty" bestaat het kind <strong> niet meer binnen de alinea. Als je msg.textContent = "<b>Hi</b>" instelt, verschijnen de letterlijke tekens “Hi”; er wordt geen vet element gemaakt.
Tekstwaarden zijn strings. Als een teller “4” bevat, levert count.textContent + 1 de waarde “41” op. Converteer voordat je optelt:
count.textContent = Number(count.textContent) + 1;
De optelling geeft het getal 5 en de toewijzing toont de tekstvorm daarvan, “5”.
Lees tekst die de lay-out volgt
Bij een gerenderd element volgt innerText de weergegeven tekst en lay-out. De eigenschap laat nakomelingen weg die met display: none zijn verborgen en bevat regeleinden die de lay-out volgen. Voor het uitlezen kan een lay-outberekening nodig zijn. Gebruik textContent voor gewone tekstbewerkingen; kies innerText wanneer je de gerenderde tekst nodig hebt. Als het element zelf is losgekoppeld of niet wordt gerenderd, valt innerText terug op de tekstinhoud ervan.
Ontleed HTML bewust
innerHTML leest de opmaak binnen een element. Als je de eigenschap instelt, wordt de string ontleed en worden de kinderen vervangen:
msg.innerHTML = "Total: <strong>5</strong> items";
Dit maakt een nieuw <strong>-element. Het is geschikt voor opmaak die je zelf hebt geschreven en beheert. Gebruik voor tekst van een gebruiker of externe gegevens textContent en bouw structuur met createElement().
Het invoegen van niet-vertrouwde HTML kan cross-site scripting (XSS) mogelijk maken: code die door een aanvaller wordt beheerd, wordt uitgevoerd in de browser van de bezoeker. Een geïnjecteerde afbeelding kan een attribuut onerror bevatten dat code uitvoert wanneer de afbeelding niet kan worden geladen. Scripttags die via innerHTML worden ingevoegd, worden niet uitgevoerd, maar dat maakt andere geïnjecteerde HTML niet veilig. Als je alleen scripttags blokkeert, blijft deze aanvalsroute open.
Behoud bestaande kinderen wanneer je inhoud toevoegt
list.innerHTML += "<li>New</li>" leest de bestaande opmaak, voegt een string eraan toe en ontleedt en vervangt vervolgens de volledige verzameling kinderen. Hun objectidentiteit blijft niet behouden. Een variabele die een oud kind bevat, bevat nog steeds dat losgekoppelde object en getypte waarden in vervangen invoerelementen kunnen verloren gaan. Gebruik append() met nieuwe knooppunten of insertAdjacentHTML("beforeend", markup) voor vertrouwde opmaak om inhoud toe te voegen zonder bestaande kinderen opnieuw te maken.
outerHTML bevat zowel de eigen tag van het element als de inhoud. Als je de eigenschap instelt, vervang je het element zelf. Een opgeslagen referentie verwijst na die vervanging nog steeds naar het oude, losgekoppelde element; die schakelt niet automatisch over naar het nieuwe element.
Belangrijkste punten
- textContent verwerkt platte tekst en vervangt de kinderen van het element bij een toewijzing.
- Converteer tekst naar een getal voordat je ermee rekent.
- innerText volgt de gerenderde lay-out; innerHTML ontleedt opmaak.
- Houd niet-vertrouwde tekst weg uit toewijzingen waarbij HTML wordt ontleed.
- innerHTML += maakt bestaande kinderen opnieuw; append() behoudt ze.
- Een toewijzing aan outerHTML vervangt het element, waardoor oude referenties naar het losgekoppelde element blijven verwijzen.
3.2 Onderscheid attributen van objecteigenschappen
Een attribuut is een naam en waarde in HTML. Een eigenschap hoort bij het JavaScript-object dat een element vertegenwoordigt. Veel standaardattributen hebben bijbehorende eigenschappen, maar die eigenschappen kunnen waarden verwerken of een ander soort toestand weergeven.
Werk met een attribuut op naam
Bij <img src="logo.png" alt="Company logo"> initialiseert de browser eigenschappen zoals img.src en img.alt. Je kunt ook methoden gebruiken die de attribuutnaam als string accepteren:
getAttribute(name)geeft een string terug, ofnullals het attribuut ontbreekt.setAttribute(name, value)voegt een attribuut toe of wijzigt het en slaat de waarde op als tekst.hasAttribute(name)geeft aan of het attribuut aanwezig is.removeAttribute(name)verwijdert het.
Zo wijzigt link.setAttribute("href", "https://example.com/help") het doel van een link. Als er geen attribuut target is, geeft link.getAttribute("target") null terug en geen lege string.
Lees de waarde die je daadwerkelijk nodig hebt
Op een pagina op https://example.com/shop/ heeft de link <a href="/about"> de attribuutwaarde “/about”. De eigenschap href is de opgeloste URL, “https://example.com/about”. Lees het attribuut wanneer je de waarde precies zoals geschreven nodig hebt en de eigenschap wanneer je de opgeloste URL nodig hebt.
Eigenschappen kunnen andere typen dan string hebben. button.disabled is een booleaanse waarde; input.maxLength is een getal. Attribuutmethoden geven nog steeds strings of null terug. Eigenschapsnamen zijn ook hoofdlettergevoelige JavaScript-namen: el.id werkt, terwijl el.ID een andere eigenschap is en normaal gesproken undefined is.
De meeste namen zijn bekend, maar er zijn uitzonderingen. Het HTML-attribuut class is toegankelijk via className en classList. Het attribuut for van een label is de eigenschap htmlFor:
label.htmlFor = "email";
Dit koppelt het label aan het element waarvan de id “email” is.
Behandel booleaanse attributen op basis van aanwezigheid
Booleaanse attributen zijn onder meer disabled, checked, required en readonly. Door de aanwezigheid is het attribuut waar, ook als de tekst “false” is. Deze code schakelt een knop uit:
button.setAttribute("disabled", "false");
Om de knop in te schakelen, stel je button.disabled = false in of roep je button.removeAttribute("disabled") aan. button.toggleAttribute("disabled", isBusy) voegt het attribuut toe als isBusy waar is en verwijdert het als die waarde onwaar is.
Beschrijf bedieningselementen toegankelijk
ARIA-attributen geven informatie aan ondersteunende technologie. Attribuutmethoden zijn handig om ze in te stellen, zoals button.setAttribute("aria-label", "Close dialog") om een knop met alleen een pictogram een naam te geven. Hun waarden zijn strings; een waarde voor de uitgeklapte toestand is bijvoorbeeld “true” of “false”.
Gebruik eigenschappen voor gebruikelijke bewerkingen zoals img.src = "photo.jpg" of input.disabled = true. Gebruik attribuutmethoden wanneer de naam in een variabele staat, de precieze geschreven waarde van belang is of het attribuut geen bijbehorende eigenschap heeft die je gebruikt.
Volg een eigenschapswijziging terug naar HTML
const field = document.createElement("input");
field.disabled = true;
console.log(field.hasAttribute("disabled"));
console.log(typeof field.disabled);
console.log(typeof field.getAttribute("disabled"));
field.removeAttribute("disabled");
console.log(field.disabled);
De uitvoer is true, “boolean”, “string” en false. Als je de eigenschap instelt, wordt het booleaanse attribuut toegevoegd. Als je dat attribuut uitleest, krijg je nog steeds tekst terug, ook al is de eigenschap booleaans. Als je het verwijdert, wordt de eigenschap weer onwaar. De methode en de eigenschap geven dezelfde aanwezigheid weer via verschillende waardetypen.
Belangrijkste punten
- Attributen bewaren HTML-waarden; eigenschappen kunnen waarden met een type of verwerkte waarden bieden.
- getAttribute() geeft een string of, als het attribuut ontbreekt, null terug.
- Booleaanse attributen zijn waar door hun aanwezigheid, ook bij disabled="false".
- Gebruik eigenschapsnamen zoals className en htmlFor waar de HTML-namen verschillen.
- ARIA-waarden zijn strings die het element beschrijven voor ondersteunende technologie.
3.3 Koppel elementen aan gegevens en lees velden uit
Een element kan een id bevatten voor de gegevens die het weergeeft, zonder die id op het scherm te tonen. Formulierbedieningselementen bevatten ook waarden, maar hun actuele inhoud lees je via eigenschappen uit. Beide soorten waarden moeten vaak worden geconverteerd voordat je ze vergelijkt of ermee rekent.
Sla zelfgekozen gegevens op met data-attributen
HTML-namen die beginnen met data- bewaren informatie voor scripts:
<li data-task-id="17" data-priority="high">Prepare slides</li>
Het object dataset maakt deze attributen toegankelijk. Verwijder het voorvoegsel data- en verander elk streepje gevolgd door een kleine letter in die hoofdletter: data-task-id wordt dataset.taskId. data-priority wordt dataset.priority.
li.dataset.dueDate = "2026-11-05";
delete li.dataset.priority;
De toewijzing maakt data-due-date="2026-11-05". De delete verwijdert data-priority. Data-attributen kunnen ook worden geselecteerd met CSS-attribuutselectors, zoals '[data-priority="high"]'.
Een zelfbedacht attribuut zoals taskid="17" is ongeldige HTML en maakt geen eigenschap li.taskid. getAttribute("taskid") kan het nog steeds uitlezen, maar data-task-id is de juiste vorm voor zelfgekozen gegevens.
Converteer stringwaarden bewust
li.dataset.taskId is “17”, een string. li.dataset.taskId === 17 is onwaar omdat de typen verschillen. Als id's in de gegevens getallen zijn, gebruik dan Number(li.dataset.taskId) === 17. Een ontbrekend data-attribuut geeft undefined. De toewijzing li.dataset.count = 3 slaat de tekst “3” op.
Dit vormt een bruikbare verbinding van een weergegeven item terug naar het bijbehorende object:
const id = Number(li.dataset.taskId);
const task = tasks.find(task => task.id === id);
De vergelijking gebruikt nu twee getallen. Als geen object die id heeft, geeft find() undefined terug; controleer dit voordat je eigenschappen uitleest.
Lees de actuele waarde van een veld
Een <input> bevat de getypte waarde niet als tekstinhoud. Lees input.value uit, dat een string is, of wijs er een waarde aan toe om het veld te wijzigen. input.value = "" maakt het veld leeg.
Bij <input id="qty" value="1"> is qty.value gelijk aan “3” nadat de gebruiker 3 heeft getypt, maar qty.getAttribute("value") is nog steeds “1”. Het attribuut levert de beginwaarde; de eigenschap levert de actuele waarde. Een selectievakje werkt op vergelijkbare wijze: de eigenschap checked geeft de actuele booleaanse toestand aan, terwijl het attribuut de aanvankelijke geselecteerde toestand beschrijft.
Gebruik voor elk bedieningselement de juiste waarde
Zelfs <input type="number"> heeft een value die een string is. Als de hoeveelheid “3” is en elk item 0,25 kg weegt, geeft Number(qty.value) * 0.25 de waarde 0,75 kg. Maar qty.value + 1 geeft “31”, omdat + een string en een getal samenvoegt. Een <select> geeft de waarde van de geselecteerde optie terug via select.value. Lees voor een selectievakje checkbox.checked uit, niet checkbox.value, wanneer je wilt weten of het is geselecteerd.
Belangrijkste punten
- dataset koppelt data-task-id aan taskId en slaat stringwaarden op.
- Gebruik delete op een dataset-eigenschap om het bijbehorende data-attribuut te verwijderen.
- Converteer id's uit gegevens voordat je ze strikt vergelijkt met numerieke id's.
- Lees de actuele inhoud van input en select uit via value.
- Lees de actuele selectie van een selectievakje uit via checked.
- De beginattributen value en checked kunnen verschillen van de actuele eigenschappen van bedieningselementen.
4Beheer uiterlijk en zichtbaarheid
JavaScript kan het uiterlijk van een pagina wijzigen door klassen te schakelen, een berekende inlinewaarde in te stellen of een onderdeel te verbergen. Deze keuzes werken samen met de CSS die al op de pagina staat. Leer welke toestand in een klasse thuishoort, welke waarden een eenheid nodig hebben en hoe je de stijl uitleest die de browser toepast. Tonen en verbergen hebben ook gevolgen voor de lay-out en ondersteunende technologie, dus houd zichtbare panelen en hun toegankelijkheidsattributen op elkaar afgestemd.
4.1 Schakel klassen zonder de basisopmaak te verliezen
Bewaar vaste vormgevingsregels in CSS en laat JavaScript vervolgens de klassen wijzigen waarmee die regels worden geselecteerd. Een klasse kan een toestand zoals “voltooid”, “actief” of “fout” uitdrukken zonder de bijbehorende kleuren en decoraties in code te herhalen.
Voeg klassenamen toe en verwijder ze
Stel dat het stijlblad bevat:
.done { text-decoration: line-through; color: #888; }
item.classList.add("done") past het uiterlijk voor een voltooid item toe. item.classList.remove("done") verwijdert die toestand en laat andere klassen intact. Beide methoden accepteren meerdere namen; een bestaande klasse toevoegen of een ontbrekende verwijderen kan geen kwaad.
contains("done") geeft een booleaanse waarde terug. replace("wide", "narrow") vervangt een aanwezige klasse door een andere. toggle("active") voegt een ontbrekende klasse toe of verwijdert een aanwezige en geeft terug of de klasse daarna bestaat.
Volg een klassewijziging
Begin met <div class="card">:
card.classList.add("active", "wide");
const active = card.classList.toggle("active");
const replaced = card.classList.replace("wide", "narrow");
Na de eerste regel zijn de klassen “card active wide”. Het schakelen verwijdert “active”, dus active is false en de klassen worden “card wide”. Het vervangen van “wide” laat “card narrow” over en geeft true terug. Een latere card.classList.contains("active") is false.
Stel een klasse in op basis van een voorwaarde
Wanneer gegevens de gewenste toestand bepalen, geef je een tweede argument door:
row.classList.toggle("overdue", daysLeft < 0);
Een negatieve daysLeft zorgt dat de klasse aanwezig is; anders ontbreekt de klasse. Als je de aanroep herhaalt, blijft die toestand behouden. Een gewone toggle("overdue") zou de toestand bij elke aanroep omkeren.
Behoud de rest van het klasseattribuut
className is de volledige klassestring. card.className = "active" vervangt alle bestaande klassen, waaronder “card”. Gebruik deze toewijzing als je de hele verzameling wilt vervangen; gebruik classList voor wijzigingen van afzonderlijke toestanden.
Geef alleen klassenamen door, zonder leestekens van CSS-selectors. classList.add(".active") voegt een klassenaam met een letterlijke punt toe; dat is niet de klasse die overeenkomt met .active. Eén argument mag geen spaties bevatten: classList.add("big red") veroorzaakt een InvalidCharacterError. Schrijf classList.add("big", "red") voor twee klassen.
Controleer de CSS als het uiterlijk niet verandert
Als een klasse geen zichtbaar effect heeft, inspecteer dan de klassenaam en de regel in DevTools. Controleer of een regel ontbreekt of verkeerd is gespeld en of er overschreven declaraties zijn doorgestreept in het deelvenster Styles.
Belangrijkste punten
- classList wijzigt afzonderlijke klassenamen en behoudt andere klassen.
- toggle(name) geeft terug of de klasse daarna aanwezig is.
- toggle(name, condition) stelt een klasse in op basis van gegevens zonder die bij elke uitvoering om te keren.
- Een toewijzing aan className vervangt de volledige klassestring.
- Geef afzonderlijke klassenamen door, zonder selectorpunten of spaties binnen een naam.
4.2 Stel berekende stijlen in en lees toegepaste stijlen uit
Gebruik klassen voor vaste ontwerpen en inlinestijlen voor berekende waarden. Het object style leest en schrijft inlinedeclaraties, niet alle regels die invloed hebben op een element.
Schrijf CSS-waarden via style
CSS-namen met streepjes worden camelCase-eigenschappen in JavaScript. background-color wordt backgroundColor, font-size wordt fontSize en z-index wordt zIndex:
box.style.backgroundColor = "gold";
box.style.width = "250px";
Stijlwaarden zijn strings. Neem een eenheid op wanneer de eigenschap die vereist. Op een pagina in de standaardmodus wordt de toewijzing box.style.width = 250 genegeerd, omdat een breedte die niet nul is een CSS-eenheid nodig heeft. De string “0” is geldig voor een breedte van nul.
style.setProperty() gebruikt daarentegen de CSS-schrijfwijze:
box.style.setProperty("background-color", "gold");
document.documentElement.style.setProperty("--accent", "#0a7d5a");
De CSS-variabele op het hoofdelement levert de waarde voor regels die naar var(--accent) verwijzen.
Zet een berekening om in een CSS-waarde
Een voortgangsbalk toont 3 voltooide taken van de 8:
const percent = (3 / 8) * 100;
bar.style.width = `${percent}%`;
De verhouding 0,375 wordt 37,5 procent. De templateliteral levert “37.5%”, inclusief de vereiste eenheid.
Verwijder een tijdelijke overschrijving
Stel box.style.backgroundColor = "" in of roep box.style.removeProperty("background-color") aan om die inlinedeclaratie te verwijderen. De browser past dan de overige regels uit het stijlblad toe. Gebruik de CSS-naam met streepjes bij removeProperty().
Wees voorzichtig met style.cssText. De toewijzing box.style.cssText = "color: red" vervangt de volledige inlinestijl, zodat een bestaande inlinebreedte verloren gaat. Als je één stijleigenschap wijzigt, blijven de andere inlinedeclaraties intact.
Lees wat de browser toepast
Als een stijlblad een alinea rood maakt maar de alinea geen inlinekleur heeft, is p.style.color een lege string. Gebruik getComputedStyle(p).color voor de toegepaste waarde, vaak “rgb(255, 0, 0)”. Berekende waarden zijn alleen-lezen; wijzig de klasse of inlinedeclaratie om het uiterlijk te veranderen.
Inlinedeclaraties gaan vóór gewone regels uit het stijlblad, maar toepasselijke declaraties met !important kunnen voorrang krijgen. Als een klassewijziging geen effect lijkt te hebben, controleer dan of er een inlinestijl is achtergebleven die de regel overschrijft.
Belangrijkste punten
- style leest en schrijft inlinedeclaraties; camelCase komt overeen met CSS-namen met streepjes.
- Geef waar nodig eenheden op in strings met CSS-waarden.
- setProperty() en removeProperty() accepteren CSS-namen met streepjes.
- Verwijder een inlinedeclaratie om regels uit het stijlblad weer te laten gelden.
- getComputedStyle() geeft toegepaste waarden terug, inclusief stijlen uit CSS-regels.
4.3 Verberg inhoud en houd de toestand duidelijk
Als je een paneel verbergt, blijft het in het DOM, zodat het met de bestaande inhoud en veldwaarden kan terugkeren. Als je het verwijdert, haal je het uit de boom. Kies voor verbergen bij een paneel dat terugkomt en voor verwijderen bij een item waarvan de gegevens niet meer bestaan.
Gebruik de eigenschap hidden
panel.hidden = true voegt de gewone verborgen toestand toe. De standaardopmaak van de browser verbergt het paneel zonder ruimte in de lay-out over te laten. panel.hidden = false verwijdert die toestand en toont het paneel weer.
Een stijlblad kan deze standaardinstelling overschrijven. Zo kan .panel { display: flex; } een verborgen paneel zichtbaar maken. Neem het volgende op waar de verborgen toestand altijd voorrang moet hebben:
[hidden] { display: none !important; }
Je kunt de zichtbaarheid ook met een CSS-klasse regelen. Bij .is-hidden { display: none; } voegt menu.classList.toggle("is-hidden", !isOpen) de verbergklasse toe als het menu gesloten is. Controleer het stijlblad als de klasse aanwezig is maar een andere displaydeclaratie voorrang heeft.
Vergelijk drie manieren om te verbergen
display: none verwijdert de ruimte van het element uit de lay-out en verbergt het voor schermlezers. visibility: hidden maakt het onzichtbaar terwijl de ruimte behouden blijft en verbergt het ook voor schermlezers. opacity: 0 maakt het transparant maar behoudt de ruimte; er kan nog steeds op worden geklikt en het blijft beschikbaar voor schermlezers. Alleen transparantie is daarom geen goede manier om een paneel te sluiten dat niet langer beschikbaar mag zijn.
Deze effecten gaan over zichtbaarheid en lay-out, niet over verwijdering. Een verborgen invoerveld kan de getypte waarde behouden omdat hetzelfde invoerobject in de boom blijft.
Houd de beschrijving van het bedieningselement actueel
Een knop die bij een uitklapbaar paneel hoort, moet aangeven of het paneel is uitgeklapt. Stel aria-expanded in op de string “true” als het open is en “false” als het gesloten is. Baseer die waarde en de zichtbaarheid van het paneel op dezelfde toestand.
Voer voor een antwoordpaneel dat begint als <div id="answer-1" hidden>, met referenties genaamd answer en button, het volgende uit:
const willOpen = answer.hidden;
answer.hidden = !willOpen;
button.setAttribute("aria-expanded", String(willOpen));
Aanvankelijk is answer.hidden gelijk aan true, dus is willOpen waar. De toewijzing stelt hidden in op onwaar en toont het paneel. Het attribuut van de knop wordt “true”. Als je dezelfde instructies opnieuw uitvoert, begin je met hidden op onwaar, verberg je het paneel en schrijf je “false” naar het attribuut.
Onderzoek een verschil
Als de knop “uitgeklapt” aankondigt terwijl het paneel verborgen is, zijn de twee waarden niet samen bijgewerkt. Als hidden waar is maar het paneel nog zichtbaar is, inspecteer dan de berekende display en de verantwoordelijke CSS-regel. Het eerste probleem is een inconsistente toestand van de toepassing; bij het tweede overschrijft een stijl de verborgen toestand. Door zowel de DOM-eigenschappen als de toegepaste CSS uit te lezen, kun je ze onderscheiden.
Belangrijkste punten
- hidden houdt inhoud in het DOM terwijl die met de standaardopmaak wordt verborgen.
- Een expliciete displayregel kan hidden overschrijven; inspecteer de bedoelde regel of dwing die af.
- display: none verwijdert de ruimte; visibility: hidden behoudt die.
- Bij opacity: 0 blijven interactie en toegang voor schermlezers mogelijk.
- Werk aria-expanded bij op basis van dezelfde open toestand als het paneel.
5Bouw en wijzig de paginastructuur
De paginastructuur kan veranderen terwijl de pagina openstaat. Bouw een element in het geheugen, vul het en voeg het op de juiste plaats in de boom in. Dezelfde invoegmethoden kunnen een bestaand knooppunt verplaatsen, dus een referentie twee keer toevoegen maakt geen twee kopieën. Verwijderen, vervangen en klonen hebben verschillende gevolgen voor de boom en voor de referenties die je script bewaart. Door die referenties te volgen, begrijp je waarom een oude variabele soms naar losgekoppelde inhoud verwijst.
5.1 Maak een knooppunt, vul het en voeg het in
Een nieuw element verschijnt niet alleen doordat je het hebt gemaakt. Maak eerst het object, geef het daarna inhoud en attributen en voeg het ten slotte in het document in. Vóór het invoegen kun je een hele geneste structuur in het geheugen samenstellen.
Bouw één volledig item
const li = document.createElement("li");
li.textContent = "Water the plants";
li.className = "task";
li.dataset.id = "4";
document.querySelector("#tasks").append(li);
createElement("li") maakt een leeg element. De volgende regels vullen het; de laatste voegt het in als laatste kind van de bestaande takenlijst. Dit levert <li class="task" data-id="4">Water the plants</li> op. De aanroep heeft een tagnaam nodig, geen opmaak: createElement("<li>") veroorzaakt een InvalidCharacterError. Stel klassen en attributen in nadat je het element hebt gemaakt.
Voor geneste inhoud maak je afzonderlijk een span voor de titel en een knop, stel je hun tekst in en roep je li.append(title, button) aan. Voeg daarna het samengestelde item in de lijst in. document.createTextNode("…") maakt rechtstreeks tekst; als je een string aan append() doorgeeft, wordt ook een tekstknooppunt ingevoegd.
Kies een invoegpositie
parent.append(...)voegt toe na de bestaande kinderen.parent.prepend(...)voegt toe vóór de bestaande kinderen.element.before(...)voegt eerdere knooppunten met dezelfde ouder toe.element.after(...)voegt volgende knooppunten met dezelfde ouder toe.
Elke methode accepteert meerdere knooppunten en strings. Strings worden als tekst behandeld, dus list.append("<li>New</li>") bouwt geen item. De punthaken verschijnen als tekens binnen de lijst.
Oudere methoden komen nog steeds voor in code. appendChild(node) accepteert één knooppunt en geeft het terug; de methode accepteert geen string. append() geeft undefined terug. parent.insertBefore(newNode, referenceNode) voegt een knooppunt in vóór een bestaand kind; met null als referentie voeg je aan het einde toe.
Begrijp het verschil tussen verplaatsen en kopiëren
Een knooppunt kan maar één plaats in de boom innemen. Als je een bestaand knooppunt invoegt, verplaats je het. Bij een lijst in de volgorde a, b, c verplaatst list.prepend(list.lastElementChild) c naar het begin, zodat c, a, b ontstaat. Er blijft geen tweede c aan het einde staan.
Dit verklaart ook een veelvoorkomende lusfout: als je één <li> buiten een lus maakt en die herhaaldelijk toevoegt, blijft er één item over. Elke iteratie wijzigt en verplaatst hetzelfde object. Maak bij elke iteratie een nieuw element binnen de lus wanneer de pagina meerdere items nodig heeft, of maak afzonderlijke klonen.
Voeg vertrouwde opmaak naast bestaande inhoud in
insertAdjacentHTML(position, markup) ontleedt HTML zonder bestaande kinderen te vervangen. De vier positienamen zijn "beforebegin" en "afterend" voor knooppunten met dezelfde ouder buiten het element, en "afterbegin" en "beforeend" voor kinderen binnen het element. list.insertAdjacentHTML("beforeend", "<li>New</li>") voegt een ontleed item toe. Gebruik dit alleen voor vertrouwde opmaak; externe tekst hoort in textContent. insertAdjacentElement() en insertAdjacentText() gebruiken dezelfde positienamen voor een element of platte tekst.
Belangrijkste punten
- Maken, vullen en invoegen zijn afzonderlijke stappen.
- append/prepend voegen kinderen toe; before/after voegen knooppunten met dezelfde ouder toe.
- Een string aan append() doorgeven voegt tekst in zonder HTML te ontleden.
- Een bestaand knooppunt invoegen verplaatst het in plaats van het te kopiëren.
- Maak bij elke iteratie een nieuw item binnen de lus wanneer je meerdere objecten nodig hebt.
- appendChild() accepteert één knooppunt en geeft het terug; append() accepteert meerdere invoerwaarden en geeft undefined terug.
- insertAdjacentHTML() behoudt bestaande kinderen, maar ontleedt de invoer nog steeds als HTML.
5.2 Verwijder, vervang en kloon de juiste objecten
Een element verwijderen verandert de boom, maar wist niet elke referentie naar dat object. Bij vervangen ontstaat een vergelijkbaar onderscheid: het nieuwe object neemt de plaats in, terwijl opgeslagen variabelen nog naar het oude kunnen verwijzen.
Verwijder één element of meerdere overeenkomsten
element.remove() koppelt dat element los. parent.removeChild(child) is de oudere vorm via de ouder en geeft het verwijderde knooppunt terug. Als een variabele het knooppunt nog bevat, kan het script het uitlezen of later opnieuw invoegen.
Om voltooide taken te verwijderen, selecteer je een statische collectie en doorloop je die met een lus:
document.querySelectorAll(".task.done")
.forEach(task => task.remove());
Bij vijf taken, waarvan er twee als voltooid zijn gemarkeerd, blijven er zo drie over. Een element verwijderen verandert niet welke referenties de statische NodeList bevat, dus de lus bezoekt beide geselecteerde taken.
Tel niet vooruit door een krimpende dynamisch bijgewerkte lijst
list.children wordt dynamisch bijgewerkt. Bij zes kinderen verwijdert een voorwaartse lus die items[i] verwijdert er maar drie. Na de eerste verwijdering schuift het tweede element naar index 0, maar i gaat verder naar 1. Het volgende oorspronkelijke kind wordt overgeslagen en dezelfde verschuiving herhaalt zich.
Maak een momentopname voordat je alle huidige kinderen verwijdert:
Array.from(list.children).forEach(item => item.remove());
Om een container alleen leeg te maken, is list.replaceChildren() duidelijker. De container wordt ook leeg als je list.textContent = "" of list.innerHTML = "" instelt. Een lege string ontleedt geen externe inhoud.
Vervang één knooppunt of alle kinderen
old.replaceWith(newElement) zet een nieuw knooppunt op de plaats van het oude. Bij <p id="status">Loading…</p> vervangt document.querySelector("#status").replaceWith(list) het bericht door de lijst. parent.replaceChildren(a, b, c) vervangt alle kinderen van de ouder in één bewerking en behoudt de ouder zelf.
Dit verschil is van belang voor opgeslagen referenties. Een variabele die de ouder bevat, blijft na replaceChildren() naar de ouder verwijzen, maar referenties naar de verwijderde kinderen wijzen nu naar losgekoppelde objecten. Als je een container vervangt met replaceWith(), wordt ook die container losgekoppeld.
Kopieer het element met of zonder nakomelingen
element.cloneNode(true) maakt een diepe kopie, inclusief nakomelingen en attributen. cloneNode() of cloneNode(false) kopieert het element en de attributen zonder de kinderen. Een gekloond lijstitem zonder nakomelingen bevat geen tekst van het oorspronkelijke item.
Een kloon is aanvankelijk losgekoppeld en moet worden ingevoegd. De kloon neemt ook de id van het origineel over. Geef de kloon een nieuwe id of verwijder dat attribuut voordat je die op dezelfde pagina plaatst, zodat selectie op id betrouwbaar blijft.
Handel optionele elementen af
Als een zoekopdracht niets kan vinden, roep dan niet direct een methode aan op het resultaat. document.querySelector("#promo").remove() veroorzaakt een fout als er geen promotie bestaat. document.querySelector("#promo")?.remove() doet in dat geval veilig niets. Bij een verplichte container is een ontbrekend resultaat een nuttig signaal om de selector en het uitvoeringstijdstip van het script te controleren voordat je de structuur probeert bij te werken.
Belangrijkste punten
- remove() koppelt een knooppunt los; via een opgeslagen referentie kun je het nog gebruiken of opnieuw invoegen.
- Gebruik een statische lijst wanneer je meerdere geselecteerde elementen verwijdert.
- replaceChildren() behoudt de container en vervangt of verwijdert de kinderen.
- replaceWith() vervangt het geselecteerde knooppunt zelf.
- cloneNode(true) kopieert nakomelingen; een oppervlakkige kloon laat ze weg.
- Klonen kopieert id's, dus wijzig of verwijder een gekopieerde id vóór het invoegen.
6Zet gegevens om in een pagina
Arrays beschrijven wat een pagina moet tonen; renderen zet die beschrijvingen om in elementen. Begin met één item, breid het patroon uit naar lijsten en tabellen en organiseer herhaalde opmaak daarna met fragmenten of templates. Een renderfunctie maakt latere updates voorspelbaar wanneer de gegevens veranderen. Houd de oorspronkelijke array, de geselecteerde weergave en de weergegeven elementen uit elkaar, zodat filters, sortering, lege resultaten en overzichten consistent blijven.
6.1 Render arrayitems als lijstitems en tabelrijen
Renderen betekent dat je gegevens omzet in een zichtbare DOM-structuur. Houd de array als bron en bouw voor elk object een element. Plaats gegevenswaarden in textContent, zodat ze tekst blijven, ook als ze punthaken bevatten.
Bouw voor elk object één element
Gebruik deze boekobjecten:
const books = [
{ id: 1, title: "Dune", pages: 412 },
{ id: 2, title: "Emma", pages: 474 },
{ id: 3, title: "Beloved", pages: 324 }
];
function createBookItem(book) {
const li = document.createElement("li");
li.dataset.id = String(book.id);
li.textContent = `${book.title} (${book.pages} pages)`;
return li;
}
const list = document.querySelector("#books");
list.append(...books.map(createBookItem));
map() roept de opbouwfunctie eenmaal per boek aan en levert drie afzonderlijke elementen op. Spreadsyntaxis geeft die elementen als afzonderlijke argumenten door aan append(). De weergave luidt “Dune (412 pages)”, “Emma (474 pages)” en “Beloved (324 pages)”. De pagina-aantallen tellen op tot 1.210.
Zonder spreadsyntaxis ontvangt list.append(books.map(createBookItem)) één array. De methode zet die array om in tekst met strings zoals “[object HTMLLIElement]” in plaats van de itemelementen in te voegen.
De opgeslagen id koppelt het weergegeven element aan de gegevens. Lees Number(li.dataset.id) uit voordat je die waarde vergelijkt met numerieke boek-id's en gebruik daarna books.find(book => book.id === id).
Handel ontbrekende en lege gegevens af
Als een optioneel auteursveld ontbreekt, toont directe interpolatie “undefined”. Gebruik book.author ?? "Unknown author" als terugvaloptie wanneer het veld null of undefined is. Terugval bij null of undefined laat andere waarden, waaronder 0 en een lege string, ongewijzigd.
Als de array leeg is, toon dan een bericht zoals “Nog geen boeken”. Een leeg resultaat moet de gebruiker vertellen dat er momenteel geen items zijn. Vervang bij opnieuw renderen de oude weergave, zodat een eerder bericht of eerdere items niet naast het nieuwe resultaat blijven staan.
Begrijp wat een aanpak met HTML-strings doet
Een vertrouwde array kan worden omgezet in HTML-strings die je met join("") samenvoegt voordat je ze aan innerHTML toewijst. Door het samenvoegen verdwijnen de komma's die bij conversie van de array naar een string anders zouden worden ingevoegd. Deze aanpak ontleedt elke geïnterpoleerde waarde als HTML. Gebruik de aanpak waarbij je elementen opbouwt als waarden van externe bronnen kunnen komen.
Bouw een geldige tabelstructuur
Bouw voor tabelgegevens één <tr> per object en één <td> voor elk weergegeven veld. Voeg de rijen toe aan de <tbody> van de tabel. Voor metingen uit Oslo bij 4,25 °C en Caïro bij 28,5 °C kan de temperatuurcel reading.temp.toFixed(1) gebruiken: dit toont “4.3” en “28.5”. toFixed() geeft een string terug met het gevraagde aantal decimalen. toLocaleString() maakt daarentegen de waarde op volgens de landinstelling van de gebruiker, die een decimale komma kan gebruiken. Pas de opmaak toe bij de weergave, zodat numerieke gegevens beschikbaar blijven voor berekeningen.
Bouw beide cellen voordat je de rij invoegt
Voor een bestaand leeg tabelgedeelte met de naam tbody rendert dit de metingen:
const readings = [{ city: "Oslo", temp: 4.25 }, { city: "Cairo", temp: 28.5 }];
const rows = readings.map(reading => {
const row = document.createElement("tr");
const city = document.createElement("td");
const temperature = document.createElement("td");
city.textContent = reading.city;
temperature.textContent = reading.temp.toFixed(1) + " °C";
row.append(city, temperature);
return row;
});
tbody.replaceChildren(...rows);
Elke iteratie maakt een nieuwe rij en twee nieuwe cellen. Door beide cellen te vullen voordat je de rij toevoegt, blijft de veldvolgorde expliciet. Door rows met spreadsyntaxis door te geven, bied je de twee rijknooppunten afzonderlijk aan; de laatste vervanging verwijdert ook eventuele eerdere rijen.
Belangrijkste punten
- Bouw voor elk gegevensobject een afzonderlijk element en vul waarden in met textContent.
- Geef een array met knooppunten via spreadsyntaxis door aan append().
- Gebruik data-attributen om weergegeven elementen aan objecten te koppelen.
- Zorg voor berichten bij een lege lijst en terugvalopties voor null of undefined.
- Plaats tabelrijen in tbody en velden in cellen.
- toFixed() geeft weergavetekst terug; bewaar numerieke gegevens voor berekeningen.
6.2 Stel herhaalde inhoud samen vóór het invoegen
Als een lijst veel items bevat, bouw je de nieuwe inhoud buiten de pagina op en voeg je die samen in. Een DocumentFragment groepeert knooppunten zonder een omhullend element toe te voegen. Met een template schrijf je een herhaalde structuur in HTML en vul je voor elk object een nieuwe kopie.
Verzamel knooppunten in een fragment
const fragment = document.createDocumentFragment();
for (const book of books) {
fragment.append(createBookItem(book));
}
list.append(fragment);
Het fragment begint buiten het document. Elk nieuw item wordt een kind ervan. Als je het fragment toevoegt, worden de kinderen in hun bestaande volgorde naar de lijst verplaatst; het fragment zelf wordt niet als omhullend element ingevoegd. Nadat 100 items naar een lege lijst zijn verplaatst, heeft de lijst 100 kinderen en het fragment 0.
Dit patroon groepeert het invoegen en houdt de opbouwcode overzichtelijk. Het garandeert geen bepaalde snelheidswinst. Een array met opgebouwde knooppunten werkt ook: list.append(...items) voegt ze toe, terwijl list.replaceChildren(...items) de huidige inhoud ermee vervangt.
Definieer herhaalde opmaak in een template
<template id="book-row">
<li class="book"><span class="title"></span>
(<span class="pages"></span> pages)</li>
</template>
De browser ontleedt deze opmaak zonder die weer te geven. De inhoud staat in een afzonderlijk DocumentFragment op template.content. Een zoekopdracht op documentniveau doorzoekt dat fragment niet. Selecteer de template, kloon de inhoud en zoek daarna binnen de kloon:
const template = document.querySelector("#book-row");
const clone = template.content.cloneNode(true);
clone.querySelector(".title").textContent = book.title;
clone.querySelector(".pages").textContent = book.pages;
const item = clone.firstElementChild;
list.append(clone);
De titel en het pagina-aantal worden vóór het invoegen ingevuld. item bewaart een referentie naar de nieuwe <li>. Na het toevoegen is clone leeg omdat de kinderen zijn verplaatst, maar item verwijst nog steeds naar het ingevoegde element.
Behoud de herbruikbare bron
Voeg elke keer een kopie toe. De aanroep list.append(template.content) verplaatst de bronknooppunten uit de template. Een latere zoekopdracht binnen template.content geeft dan null terug en de volgende poging om de ontbrekende titel in te vullen veroorzaakt een fout. De brontemplate moet beschikbaar blijven voor latere boeken.
Vul voor veel kopieën elk gekloond fragment, voeg die kopieën toe aan een verzamelfragment en voeg daarna de verzameling in. Een fragment kan de kinderen van een ander fragment ontvangen, net zoals een lijst dat kan.
Kies een leesbare opbouwmethode
createElement() is geschikt voor een kleine structuur of een structuur die sterk verschilt per item. Een template is geschikt voor grotere herhaalde opmaak die als HTML gemakkelijker te bewerken is. Voeg in beide gevallen externe waarden in als tekst. Een HTML-string is geschikt voor vertrouwde opmaak, maar interpolatie daarin leidt nog steeds tot het ontleden van HTML. Kies de opbouwmethode op basis van de structuur die je moet onderhouden en houd dezelfde volgorde aan: maken of klonen, vullen en invoegen.
Verzamel ingevulde kopieën voor één vervanging
Met de bovenstaande boektemplate en een bestaande array books:
const group = document.createDocumentFragment();
for (const book of books) {
const copy = template.content.cloneNode(true);
copy.querySelector(".title").textContent = book.title;
copy.querySelector(".pages").textContent = book.pages;
group.append(copy);
}
list.replaceChildren(group);
Elke ingevulde kopie verplaatst het bijbehorende item naar group. De laatste regel vervangt de inhoud van de lijst door die items en maakt group leeg. De oorspronkelijke template blijft daarbij ongemoeid, zodat de functie de opbouw later voor een andere array kan herhalen.
Belangrijkste punten
- Een fragment toevoegen verplaatst de kinderen en laat het fragment leeg achter.
- Een fragment groepeert knooppunten zonder een omhullend element op de pagina te maken.
- Template-inhoud wordt ontleed maar staat buiten de weergegeven documentboom.
- Kloon template.content voor elk item en vul de kloon vóór het invoegen.
- Bewaar de referentie naar het item voordat het fragment dat het bevat wordt leeggemaakt.
6.3 Houd gerenderde weergaven in overeenstemming met de gegevens
Gebruik gegevens als de enige leidende gegevensbron. Een renderfunctie leidt een weergave af van de huidige array. Roep de functie aan nadat je de array of een object daarin hebt gewijzigd.
Vervang de weergave bij elke renderactie
Stel dat tasks vier objecten bevat, waarvan er precies één voltooid is, en dat taak 2 bestaat en nog niet is voltooid. Een renderfunctie kan nieuwe items en een overzicht opbouwen:
function render() {
const items = tasks.map(task => {
const li = document.createElement("li");
li.dataset.id = String(task.id);
li.textContent = task.text;
li.classList.toggle("done", task.done);
return li;
});
list.replaceChildren(...items);
const doneCount = tasks.filter(task => task.done).length;
summary.textContent = `${doneCount} of ${tasks.length} done`;
}
Na tasks.push({ id: 5, text: "Book dentist", done: false }); render(); heeft de lijst vijf items en vermeldt het overzicht “1 of 5 done”. Als je tasks.find(task => task.id === 2).done = true; render(); instelt en uitvoert, verandert dit in “2 of 5 done”.
Het vervangen van kinderen is hier essentieel. Als de functie alleen alle items zou toevoegen, zou twee keer aanroepen de weergave verdubbelen. Alleen een DOM-item verwijderen is ook tijdelijk: als het object in de array blijft staan, brengt renderen het terug. Als tasks met let is gedeclareerd, verwijder je het uit de gegevens met tasks = tasks.filter(task => task.id !== id) en render je opnieuw.
Leid een weergave af zonder de bron te verliezen
Geef bij een renderfunctie die een weergavearray accepteert tasks.filter(task => !task.done) door om alleen onvoltooide taken weer te geven. Bewaar de volledige array voor latere weergaven en tellingen van de hele lijst. Geef overzichten een duidelijke betekenis: een aantal zichtbare taken verschilt van een aantal van alle taken.
sort() wijzigt de array waarop de methode wordt aangeroepen. Sorteer voor de weergave een kopie met [...tasks].sort(...) of gebruik tasks.toSorted(...) voor een gesorteerde kopie. Geef een vergelijkingsfunctie op: numerieke waarden hebben (a, b) => a - b nodig en voor titels kun je (a, b) => a.title.localeCompare(b.title) gebruiken. De standaardsoortering vergelijkt stringvormen, dus [100, 25, 3].sort() blijft in die volgorde; numeriek sorteren geeft [3, 25, 100].
Vergelijk id's en ontleed gegevens correct
Een weergegeven dataset.id is een string. Converteer die vóór een strikte vergelijking met numerieke id's, anders kan find() undefined teruggeven ook al bestaat het bedoelde object. JSON-gegevens zijn anders: JSON.parse() behoudt JSON-getallen en booleaanse waarden als die typen. Ontlede objecten kunnen door dezelfde renderfunctie worden verwerkt als objecten die rechtstreeks in code zijn geschreven.
Behoud zo nodig lokale toestand
Een volledige heropbouw maakt nieuwe elementen. Daarbij kunnen focus en tekst die in invoervelden binnen het opnieuw opgebouwde gebied is getypt verloren gaan. Werk bij een kleine toestandswijziging waarbij die objecten behouden moeten blijven eerst de gegevens bij en daarna het bestaande item, bijvoorbeeld met li.classList.toggle("done", task.done). De gegevens moeten de wijziging nog steeds vastleggen, zodat een latere volledige renderactie overeenkomt met de huidige weergave.
Geef de weergave en het overzicht afzonderlijke invoer
Een gefilterde weergave kan nog steeds een overzicht van alle taken tonen:
function renderOpenTasks() {
const visible = tasks.filter(task => !task.done);
const nodes = visible.map(task => {
const li = document.createElement("li");
li.textContent = task.text;
return li;
});
if (visible.length === 0) {
const empty = document.createElement("li");
empty.textContent = "No open tasks";
nodes.push(empty);
}
list.replaceChildren(...nodes);
const done = tasks.filter(task => task.done).length;
summary.textContent = `${done} of ${tasks.length} done`;
}
Een array waarin alles is voltooid, toont voor deze weergave het bericht voor een lege lijst, maar behoudt elk object voor het totaal. Tellen vanuit visible zou een andere vraag beantwoorden en zou kunnen melden dat er geen voltooide taken zijn, alleen omdat deze weergave ze uitsluit.
Belangrijkste punten
- Werk de gegevens bij en leid daarna de pagina af van die gegevens.
- Vervang oude kinderen wanneer je een lijst opnieuw opbouwt om duplicaten te voorkomen.
- Filter en sorteer een afgeleide weergave en behoud zo nodig de oorspronkelijke array.
- Geef numerieke sortering een vergelijkingsfunctie en converteer dataset-id's vóór numerieke vergelijking.
- JSON.parse() behoudt numerieke en booleaanse gegevenstypen.
- Werk gericht één element bij wanneer bij opnieuw opbouwen benodigde invoertoestand of focus verloren zou gaan.
Document Object Model: voorbeelden
1Vind je weg door een paginaboom
11 stappen
- 1IntroductieBegin met een pagina die je kunt inspecteren
De browser bouwt objecten op vanuit HTML. JavaScript werkt met deze DOM-boom.
Volg een lijst met twee items van opmaak naar knooppunten en gebruik daarna familierelaties om een nabij item te bereiken. Houd DevTools open om de zichtbare pagina met de bijbehorende boom te vergelijken.
- 2UitlegBegin bij document
Het DOM is het actuele paginamodel van de browser.
documentgeeft toegang;document.bodyverwijst naar het body-element.De browser biedt deze API aan. JavaScript roept die aan om de huidige pagina te wijzigen zonder opnieuw te laden of het HTML-bestand op de server te herschrijven.
- 3VoorbeeldBekijk het element en de tekst afzonderlijk
Kijk naar
<li>Buy milk</li>. De<li>wordt een elementknooppunt en “Buy milk” wordt een tekstknooppunt als kind daarbinnen.Lees
nodeTypeuit om ze te onderscheiden: het element is type 1 en het tekstkind is type 3. Commentaar heeft type 8 en het document zelf heeft type 9. “Knooppunt” is de naam van de bredere groep; een element is één soort knooppunt. - 4VoorbeeldTel wat inspringing toevoegt
Gebruik precies deze opmaak:
<ul id="tasks"> <li>Buy milk</li> <li>Call Sam</li> </ul>De lijst heeft twee kindelementen. Die heeft ook drie tekstknooppunten met witruimte: vóór, tussen en na die items. De
children.lengthis daarom 2, terwijlchildNodes.length5 is. De extra knooppunten ontstaan door de tekens tussen de tags. - 5UitdagingVoorspel het eerste knooppunt
Welk soort knooppunt is
tasks.firstChildin de ingesprongen lijst van de vorige dia, en waarom verschilt het vantasks.firstElementChild?---reveal---
firstChildis het tekstknooppunt met witruimte vóór het eerste item.firstElementChildslaat dat knooppunt over en geeft de eerste<li>terug. Inspringing beïnvloedt de volgorde van knooppunten, ook al ontstaat er geen extra zichtbare taak. - 6TipInspecteer de actuele boom
Kies “Inspecteren” bij het eerste lijstitem. Het paneel Elements toont het actuele DOM. Als het item is geselecteerd, verwijst
$0in de console ernaar en toontconsole.dir($0)de eigenschappen ervan.De boom kan door de parser toegevoegde elementen bevatten, zoals een
<tbody>rond tabelrijen. Gebruik dit paneel om de werkelijke nesting te controleren in plaats van aan te nemen dat die met elke taggrens in de broncode overeenkomt. - 7VoorbeeldGa naar het volgende element
Sla de lijst op als
tasksen volg daarna één elementrelatie:const first = tasks.firstElementChild; const second = first.nextElementSibling;second.textContentis “Call Sam”. Als je in plaats daarvanfirst.nextSiblinguitleest, bereik je de witruimte tussen de items. Kies de elementvorm wanneer je tussen pagina-elementen wilt navigeren en tekstknooppunten moeten worden overgeslagen. - 8UitlegStop veilig bij het laatste item
De
nextElementSiblingvan het laatste item isnull. Een eigenschap rechtstreeks uit die ontbrekende referentie lezen veroorzaakt een TypeError.second.nextElementSibling?.textContentstopt daar en geeftundefined, zonder een knooppunt toe te voegen of een lege string te leveren. - 9VerbandZoek het omhullende item op betekenis
Een geneste span kan de omhullende taak vinden met
span.closest("li"). De zoekopdracht begint bij de span zelf en controleert vervolgens de voorouders één voor één totdat er een overeenkomst is.span.matches("li")toetst alleen de span en geeft in dit geval false terug. Zoeken naar een voorouder is nuttig wanneer een extra omhullend element ervoor kan zorgen dat een vast aantal stappen naar ouders op de verkeerde plaats uitkomt. - 10UitdagingNavigeer langs een toegevoegd omhullend element
Elk lijstitem omsluit de tekst nu met een span. Hoe kun je, vanaf de eerste span, de tekst van het volgende item lezen zonder afhankelijk te zijn van witruimteknooppunten of het aantal omhullende elementen binnen een item?
---reveal---
Zoek het omhullende item en daarna het volgende element met dezelfde ouder:
span.closest("li").nextElementSibling?.textContent. Het omhullende item wordt op tag gevonden en navigatie tussen alleen elementen met dezelfde ouder slaat de witruimte tussen items over. - 11SamenvattingProbeer nu een tabel
Inspecteer een tabel waarvan de broncode een rij rechtstreeks binnen
<table>plaatst. Zoek de werkelijke ouder van de rij.Vergelijk het aantal kindknooppunten en kindelementen en gebruik het paneel Elements om de door de parser toegevoegde structuur en witruimte te verklaren.
2Selecteer en wijzig de bedoelde elementen
12 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieKies een zoekopdracht voordat je een pagina wijzigt
- 2UitlegGebruik de id-syntaxis voor de methode
- 3VoorbeeldHoud een herhaalde klasse binnen de kaart
- 4TipOnderscheid een ontbrekend knooppunt van ongeldige syntaxis
- 5UitdagingVerklaar een vroeg null-resultaat
- 6VoorbeeldDoorloop de teruggegeven elementen
- 7UitlegConverteer wanneer je arraymethoden nodig hebt
- 8VoorbeeldVergelijk twee opgeslagen collecties
- 9KernpuntBekijk een krimpende dynamisch bijgewerkte collectie
- 10UitdagingKies de juiste gecombineerde selector
- 11UitdagingCombineer zoekbereik met veilig doorlopen
- 12SamenvattingOnderzoek je volgende mislukte zoekopdracht
3Werk een profiel bij en lees de formulierwaarden uit
15 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieOnderscheid de informatie die een element bevat
- 2VoorbeeldLees tekst zonder de tags
- 3UitlegBehandel externe waarden als tekens
- 4UitdagingBehoud een bestaand invoerveld
- 5VerbandLees zo nodig gerenderde tekst uit
- 6VoorbeeldLees een geschreven of opgeloste URL
- 7UitlegStel een booleaanse waarde in via aanwezigheid
- 8UitdagingHerstel een uitgeschakeld bedieningselement
- 9VoorbeeldZet een datanaam om in een eigenschapsnaam
- 10UitlegLees de actuele veldinhoud
- 11UitdagingReken met een veldwaarde
- 12VoorbeeldZoek een object met een weergegeven id
- 13TipGeef een pictogramknop een leesbare naam
- 14UitdagingVerbind gegevens opzoeken met veilig weergeven
- 15SamenvattingInspecteer een veld vóór en na bewerking
4Laat het uiterlijk een duidelijke toestand volgen
13 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieLaat gegevens de zichtbare toestand bepalen
- 2VoorbeeldBehoud een basisklasse terwijl je een toestand toevoegt
- 3UitlegGebruik een voorwaarde voor herhaalde updates
- 4UitdagingVoorspel twee herhaalde updates
- 5VoorbeeldBereken een CSS-percentage
- 6UitlegLees het resultaat van de cascade
- 7UitdagingHerstel de kleur van het stijlblad
- 8UitlegKies wat een gesloten paneel verwijdert
- 9VoorbeeldLaat een paneel en het bedieningselement overeenkomen
- 10TipControleer een stijl die hidden overschrijft
- 11UitdagingOnderzoek een onzichtbaar maar actief bedieningselement
- 12UitdagingCombineer klassen met een berekende waarde
- 13SamenvattingControleer toestand en uiterlijk afzonderlijk
5Bouw items en volg hun objectreferenties
12 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieBouw een taakitem in afzonderlijke stappen
- 2VoorbeeldMaak een losgekoppeld item
- 3VoorbeeldVoeg het voltooide item in
- 4UitlegKies kinderen of knooppunten met dezelfde ouder
- 5VoorbeeldVerplaats een bestaand knooppunt
- 6UitdagingVerklaar waarom een lus één item oplevert
- 7UitlegKoppel los zonder een referentie te verliezen
- 8VoorbeeldVervang één item of een hele weergave
- 9TipKopieer nakomelingen en controleer id's
- 10UitdagingVoorspel een oppervlakkige kopie
- 11UitdagingVerplaats het origineel en voeg een kopie in
- 12SamenvattingVolg identiteiten naast de opmaak
6Render een lijst vanuit gegevens en werk die betrouwbaar bij
17 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieLaat de array de weergave bepalen
- 2VoorbeeldSchrijf een opbouwfunctie voor één boek
- 3VoorbeeldGeef de array door als afzonderlijke knooppuntargumenten
- 4TipHoud ontbrekende gegevens leesbaar
- 5VerbandPas het patroon toe op tabelrijen
- 6UitdagingZoek uit waarom de lijst objecttekst toont
- 7VoorbeeldVerzamel knooppunten buiten de pagina
- 8UitlegBewaar herhaalde structuur in HTML
- 9VoorbeeldVul de kloon vóór het overbrengen
- 10UitdagingBehoud de herbruikbare template
- 11UitlegVervang de weergave vanuit actuele gegevens
- 12VoorbeeldWerk een object en het bijbehorende overzicht bij
- 13UitlegHoud een gesorteerde weergave apart
- 14UitdagingVerklaar een item dat na verwijdering terugkomt
- 15KernpuntBehoud de lokale invoertoestand
- 16UitdagingCombineer opzoeken met een gerichte bijwerking
- 17SamenvattingControleer het renderen in drie toestanden
Document Object Model: oefenvragen
Set 1: Lees en wijzig een pagina10 Oefenvragen
Vraag 1 van 10
Toon antwoordVerberg antwoord
Vraag 2 van 10
<ul><li>A</li> <li>B</li></ul> bevat een variabele first het eerste item. Wat geeft first.nextSibling.nodeType terug?Toon antwoordVerberg antwoord
nextElementSibling. Knooppuntnavigatie neemt tekst tussen tags mee; elementnavigatie slaat die over.Vraag 3 van 10
<section id="report"> selecteren met getElementById()?Toon antwoordVerberg antwoord
getElementById(). Het hekje hoort bij CSS-selectorsyntaxis; als je hier “#report” doorgeeft, zoek je naar een id met dat teken en vind je deze section niet.Vraag 4 van 10
flag. Code slaat const live = box.getElementsByClassName("flag") op en voert daarna for (let i = 0; i < live.length; i++) { live[i].classList.remove("flag"); } uit. Welke elementen behouden de klasse?Toon antwoordVerberg antwoord
Vraag 5 van 10
label.textContent = "<em>Saved</em>"?Toon antwoordVerberg antwoord
textContent voegt de letterlijke tekens “Saved” in. De methode ontleedt die tags niet tot een element voor nadruk; maak een element of ontleed vertrouwde HTML wanneer je structuur wilt.Vraag 6 van 10
button.setAttribute("disabled", "false") uit. Welke toestand geeft button.disabled aan?Toon antwoordVerberg antwoord
button.disabled is true. De tekst “false” kan een booleaans attribuut niet uitschakelen; verwijder het attribuut of stel de booleaanse eigenschap in op false om de knop in te schakelen.Vraag 7 van 10
input.value + 2 op?Toon antwoordVerberg antwoord
+ 2 voegt die samen tot “62”. Converteer vóór het optellen met Number(input.value) + 2 om het getal 8 te krijgen, ook wanneer het veld een numeriek invoerveld is.Vraag 8 van 10
class="card compact". Hoe kan code “selected” toevoegen met behoud van beide bestaande klassen?Toon antwoordVerberg antwoord
classList.add("selected") behoudt “card” en “compact”. Een toewijzing van de volledige klassestring vervangt ze, terwijl een punt aan het begin deel zou worden van de toegevoegde klassenaam in plaats van selectorsyntaxis te zijn.Vraag 9 van 10
list.append(list.firstElementChild)?Toon antwoordVerberg antwoord
Vraag 10 van 10
makeItem() geeft een nieuwe <li> terug. Wat voegt list.append(records.map(makeItem)) in als records twee items heeft?Toon antwoordVerberg antwoord
map() geeft een array terug en append() ontvangt die array als één argument. De methode converteert de array naar tekst met de stringrepresentaties van de elementen in plaats van de knooppunten in te voegen. Gebruik list.append(...records.map(makeItem)) om elk element als afzonderlijk argument door te geven.Set 2: Kies de juiste DOM-bewerking10 Oefenvragen
Sla deze les op om elk antwoord te zien en elke set te oefenen.
Vraag 1 van 10
<table><tr><td>8</td></tr></table>. Welk direct kindelement plaatst de parser normaal gesproken in de tabel?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
<head> selecteert een voettekst die later in <body> staat en krijgt null. De selector is correct. Welk scriptattribuut zorgt dat het script na het ontleden van de HTML wordt uitgevoerd?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
.note-elementen. Eén element verliest de klasse note en een nieuw note-element wordt toegevoegd. Wat is de lengte van de opgeslagen NodeList?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
data-record-id="38". Hoe kan code die id met strikte gelijkheid vergelijken met het getal 38?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
container.replaceChildren() aan, stelt a.textContent = "C" in en voert daarna container.append(a) en container.append(a.cloneNode(true)) uit. Wat bevat de container?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
score: 0. Wat toont record.score ?? "Pending" wanneer die waarde aan textContent wordt toegewezen?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
[{n: 14}, {n: 3}, {n: 9}]. Een weergave moet de getallen oplopend tonen met behoud van de bronvolgorde. Welke expressie bouwt die weergave?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Set 3: Volg knooppunten, toestand en collecties10 Oefenvragen
Sla deze les op om elk antwoord te zien en elke set te oefenen.
Vraag 1 van 10
entry en staat binnen een section met diezelfde klasse. Wat geeft button.closest(".entry") terug?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
.mark-elementen. Code slaat een dynamisch bijgewerkte klassecollectie en een statische NodeList met overeenkomsten op. De code verwijdert het eerste lid uit de dynamisch bijgewerkte collectie en verwijdert daarna de klasse van het nieuwe eerste lid. Wat zijn de uiteindelijke lengtes van beide collecties?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
https://example.com/catalog/ is een link geschreven als <a href="/guide">Guide</a>. Wat geeft link.getAttribute("href") terug?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
class="row done". Code voert row.classList.toggle("done", false) twee keer uit. Welke klassen blijven over?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
insertAdjacentHTML() een vertrouwde notitie invoegen als eerste kind van de section?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
template.content rechtstreeks toe aan een lijst. Waarom geeft een latere template.content.querySelector(".title") null terug?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
[{id:31, done:true}, {id:32, done:false}, {id:33, done:false}]. Code verwijdert alleen rij 31 uit het DOM, markeert taak 32 als voltooid in de array en bouwt daarna alle rijen en het overzicht volledig opnieuw op vanuit die array. Wat wordt weergegeven?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Set 4: Bouw betrouwbare gegevensgestuurde weergaven10 Oefenvragen
Sla deze les op om elk antwoord te zien en elke set te oefenen.
Vraag 1 van 10
Hello, een geneste <strong>team</strong> en een HTML-commentaar. Heeft de tekst van het strong-element dezelfde ouder als het commentaar?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
.status. Een variabele main bevat het hoofdgedeelte. Welke zoekopdracht vindt de eerste statusnakomeling daarvan?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
const field = box.querySelector("input") op. Een gebruiker wijzigt dat invoerveld van “A” in “B”. Het script voert box.innerHTML += "<span>Done</span>" uit en daarna field.value = "C". Wat gebeurt er met het zichtbare invoerveld?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
value="2". Nadat de gebruiker dit in 7 heeft veranderd, leest een script Number(input.getAttribute("value")) + 1 uit. Welk getal krijgt het script?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
panel.hidden = true, maar CSS bevat .panel { display: grid; } en het paneel blijft zichtbaar. Het bedieningselement geeft ook nog aria-expanded="true" aan. Wat herstelt beide toestanden voor een gesloten paneel?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
a, voert list.lastElementChild.before(a) uit en daarna list.prepend(list.lastElementChild). Wat is de uiteindelijke volgorde?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
author. Welke toewijzing toont “Unknown author” zonder de waarde als HTML te ontleden?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
clone.querySelector(".name").textContent = record.name. Waarom mislukt dat?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
<li> van id 12 en rendert daarna een gefilterde weergave vanuit de ongewijzigde array. Het filter behoudt alle drie objecten. Wat moet veranderen zodat id 12 na elke latere volledige renderactie verwijderd blijft?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
[{"id":24,"done":false}]. Hoe verhouden de typen van id en done zich na JSON.parse() tot data-id="24" van een element?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Set 5: Spoor fouten op in DOM-updates10 Oefenvragen
Sla deze les op om elk antwoord te zien en elke set te oefenen.
Vraag 1 van 10
<div class="card"><div class="body"><span class="label">A</span></div></div>. Vanaf het label gebruikt code parentElement.parentElement om de kaart te vinden. Tussen body en label wordt een nieuw omhullend element ingevoegd. Welke vervanging blijft betrouwbaar?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
snap = list.querySelectorAll(".new") gemaakt. Er worden twee elementen met de klasse new toegevoegd, waarna een lus over snap de klasse new verwijdert. Een nieuwe zoekopdracht op klasse wordt opgeslagen als een dynamisch bijgewerkte collectie. Wat zijn snap.length en de lengte van de dynamisch bijgewerkte collectie?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
<script>-tags eruit. Welke update behoudt het element van de voorbeeldweergave en voegt de reactie als letterlijke tekst in zonder HTML te ontleden?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
class="row selected". De gegevens zeggen dat selected false is. Code voert row.classList.toggle("selected") uit en later row.classList.toggle("selected", false). Wat zijn de twee retourwaarden en de uiteindelijke klassen?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
const open = panel.hidden op, stelt panel.hidden = !open in en schrijft String(open) naar aria-expanded. Wat zijn de uiteindelijke toestanden?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
<li id="copy-me"><span>Map</span></li> wordt gekopieerd met cloneNode(false). Wat bevat de losgekoppelde kloon?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
list.replaceChildren(fragment) aan. Welke objecten bevatten nog inhoud?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
{id: 5, done: false}. De bestaande rij heeft data-id="5" en een invoerveld met focus. Code moet het record als voltooid markeren, de bijbehorende klasse bijwerken en het invoerobject behouden. Welke volgorde past?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Kom je niet uit je eigen opgave? Huiswerkhulp
Kernbegrippen
A
Afgeleide weergave
tasks.filter(task => !task.done) zonder voltooide taken weg te gooien.append()
item.append(title, button) stelt twee kindelementen samen binnen een item voordat je het op de pagina invoegt.ARIA-attribuut
aria-label instelt op “Close dialog”, krijgt een knop met alleen een pictogram een toegankelijke naam.aria-expanded
aria-expanded="true" aangeven.Array.from()
Array.from(list.children) kan een verwijderlus elk oorspronkelijk kind bezoeken zonder verschuivende indexen.Attribuut
getAttribute() en setAttribute().href van een link kan “/help” bevatten terwijl de eigenschap een opgeloste volledige URL teruggeeft.B
Berekende stijl
getComputedStyle(title).color kan rood aangeven, ook als title.style.color leeg is.Booleaans attribuut
setAttribute("disabled", "false") omdat het attribuut bestaat.C
camelCase
backgroundColor.background-color wordt in JavaScript geschreven als style.backgroundColor.checked
checked false.classList
classList, blijven de bestaande klasse “card” en de bijbehorende basisopmaak behouden.className
className van een kaart, verwijder je de eerdere klasse “card”, tenzij je die opnieuw opneemt.closest()
closest(".product") gebruiken om de omhullende kaart te vinden.createElement()
document.createElement("li") maakt een lijstitem, maar voegt het nog niet toe aan de zichtbare lijst.Cross-site scripting
textContent voor een ingestuurde naam te gebruiken, voorkom je dat de tekens geïnjecteerde opmaak worden.CSS-eenheid
CSS-selector
"#profile .name" vindt nakomelingen met de klasse name van het profile-element.CSS-variabele
var() kunnen verwijzen."--accent" in via style.setProperty() om regels te wijzigen die naar de accentwaarde verwijzen.D
Data-attribuut
data- en informatie voor scripts opslaat zonder die als tekst weer te geven.data-id="26" kan worden gekoppeld aan het object dat de weergegeven velden heeft geleverd.dataset
row.dataset.recordId = "26" schrijft, maak of wijzig je het attribuut data-record-id.defer
Diepe kloon
display: none
Document Object Model
DocumentFragment
Dynamisch bijgewerkte collectie
E
Eigenschap
disabled geeft een booleaanse waarde terug, terwijl het uitlezen van een attribuut een string of null oplevert.Element
<ul>-element kan twee <li>-kindelementen en ook tekstknooppunten met witruimte bevatten.G
Geforceerd schakelen van een klasse
row.classList.toggle("done", task.done) houdt de rij consistent bij herhaald renderen.Gegroepeerd invoegen
replaceChildren(...items).Gerichte bijwerking
getElementById()
document.getElementById("result") zoekt naar de id “result”, zonder hekje aan het begin.H
hidden
panel.hidden = false in om een verborgen paneel te tonen zonder de inhoud opnieuw op te bouwen.HTMLCollection
list.children teruggeeft.I
Inlinestijl
bar.style.width = "60%" slaat een berekende voortgangsbreedte rechtstreeks op de balk op.innerHTML
"<strong>Ready</strong>" toewijst, ontstaat een nieuw strong-element binnen de container.innerText
innerText van een zichtbaar label laat een geneste notitie weg die met display: none is opgemaakt.insertAdjacentHTML()
insertBefore()
list.insertBefore(newItem, list.firstElementChild) plaatst het item vóór het eerste kindelement.K
Kindknooppunt
Klassenaam
classList.add(), zodat geen van beide namen een spatie bevat.Knooppunt
Knooppunt met dezelfde ouder
L
Leegtestatus
Leidende gegevensbron
Losgekoppeld knooppunt
N
NodeList
querySelectorAll() teruggeeft, bevat overeenkomende elementen.Array.from() voordat je de arraymethode map() gebruikt.null
O
Ontleden
<tbody>-element invoegen.Ontwikkelaarstools
$0 beschikbaar in de console.opacity: 0
Ouderknooppunt
<ul><li>Read</li></ul> is de lijst de directe ouder van het itemelement.outerHTML
P
prepend()
Q
querySelector()
null als niets overeenkomt..name elders het resultaat wordt.R
Renderen
Renderfunctie
replaceChildren()
replaceWith()
S
Sorteren binnen de bestaande array
[...items] voordat je sort() aanroept als de bronvolgorde ongewijzigd moet blijven.Spreadsyntaxis
list.append(...items) voegt elk opgebouwd knooppunt in in plaats van de stringrepresentatie van de array.Statische collectie
querySelectorAll() bevat geen vierde item dat na de oorspronkelijke zoekopdracht wordt toegevoegd.T
Tabelgedeelte met gegevensrijen
<tbody> die de gegevensrijen van een tabel groepeert.<tr> toe aan het geselecteerde tabelgedeelte en vult de velden in <td>-cellen.Tekstknooppunt
Template-element
Template-inhoud
template.content, dat de niet-weergegeven kindstructuur van de template bevat.Terugval bij null of undefined
?? alleen een terugvaloptie als de waarde links null of undefined is en laat andere waarden ongewijzigd.book.author ?? "Unknown author" levert leesbare tekst wanneer de optionele auteur ontbreekt.textContent
toFixed()
toFixed(1) de string “28.5” voordat die in een cel wordt ingevoegd.Typeconversie
Number(row.dataset.id) maakt het mogelijk om de opgeslagen cijfers met strikte gelijkheid te vergelijken met een numerieke object-id.V
value
Vergelijkingsfunctie
(a, b) => a - b ordent numerieke waarden van klein naar groot.visibility: hidden
Voorouderknooppunt
Over deze les
Door StudeliFout melden
Maak je eigen Studiemateriaal
Maak van je aantekeningen, slides en documenten Leermodules, Oefenvragen, Flashcards en 6 andere tools.