30. april 2026

Gennemløbe DOM'en

DOM’en tillader os at gøre alt med dens elementer og deres indhold, men først skal vi “nå det” tilsvarende DOM-objekt.

Alle operationer på DOM’en starter med document-objektet. Det er “hoveddøren” til din DOM. Fra det kan vi tilgå enhver node.

Her er et billede af links, der tillader rejse mellem DOM-noder:

Lad os diskutere dem lidt i detaljer.

I toppen: documentElement og body

De øverste trænoder er tilgængelige direkte som document-egenskaber:

<html> = document.documentElement
Den øverste document node er document.documentElement. Det er DOM-noden for <html> tagget.
<body> = document.body
En anden meget brugt DOM-node er <body>-elementet – document.body.
<head> = document.head
Tagget <head> er tilgængeligt som document.head.
Der er en hage: document.body kan være null

Et script kan ikke tilgå et element, der ikke eksisterer ved det øjeblik, hvor scriptet kører.

I særdeleshed, hvis et script er indeni <head>, så er document.body ikke tilgængeligt, fordi browseren har endnu ikke læst det.

Så, i eksemplet nedenfor viser den første alert null:

<html>

<head>
  <script>
    alert( "Fra HEAD: " + document.body ); // null, der er ikke noget <body> endnu
  </script>
</head>

<body>

  <script>
    alert( "Fra BODY: " + document.body ); // HTMLBodyElement, findes nu
  </script>

</body>
</html>
På DOM sprog betyder null at det “ikke eksisterer”

Hvis du møder null i DOM’en, betyder det “eksisterer ikke” eller “ingen sådan node”.

Children: childNodes, firstChild, lastChild

Der er to termer vi vil bruge fra nu af:

  • Child nodes (eller children/børn) – elementer der er direkte børn af et element. For eksempel er <head> og <body> børn af <html> elementet.
  • Descendants (eller efterkommere) – alle elementer der er indlejret i et givent element, inklusivt deres bør og børn af børn osv.

For eksempelt har <body> her <div> og <ul> som børn (og nogle tomme tekstnoder):

<html>
<body>
  <div>Start</div>

  <ul>
    <li>
      <b>Information</b>
    </li>
  </ul>
</body>
</html>

… og efterkommere af <body> er ikke kun børnene <div>, <ul> men også elementer der ligger dybere indlejret, såsom <li> (barn af <ul>) og <b> (et barn af <li>) – hele den del af træet.

Samlingen childNodes lister alle child nodes, inklusiv tekstnoder.

Eksemplet nedenfor viser børn af document.body:

<html>
<body>
  <div>Start</div>

  <ul>
    <li>Information</li>
  </ul>

  <div>Slut</div>

  <script>
    for (let i = 0; i < document.body.childNodes.length; i++) {
      alert( document.body.childNodes[i] ); // Text, DIV, Text, UL, ..., SCRIPT
    }
  </script>
  ...mere her...
</body>
</html>

Bemærk en interessant detalje her. Hvis vi kører eksemplet ovenfor, er det sidste element vist <script>. Faktisk har dokumentet mere indhold nedenfor, men på det tidspunkt hvor scriptet kører har browseren ikke læst det endnu, så scriptet ser det ikke.

Egenskaberne firstChild og lastChild giver hurtig adgang til første og sidste barn.

De er bare hurtige genveje. Hvis der findes børn, så er det altid sandt:

elem.childNodes[0] === elem.firstChild
elem.childNodes[elem.childNodes.length - 1] === elem.lastChild

Der er også en særlig funktion elem.hasChildNodes() til at tjekke om der er nogle børn.

DOM samlinger

Som vi kan se så ligner childNodes et array. Men det er faktisk ikke et array, men en collection (samling) – et særligt array-lignende objekt.

Det har derfor to vigtige konsekvenser for os:

  1. Vi kan bruge for..of til at iterere over den:
for (let node of document.body.childNodes) {
  alert(node); // viser alle noder fra samlingen
}

Det er fordi den er itererbar (leverer egenskaben Symbol.iterator, som det kræves).

  1. Array metode virker ikke fordi det ikke er et array:
alert(document.body.childNodes.filter); // undefined (der er ikke nogen filter-metode!)

Det første er skønt. Det andet er håndterbart, fordi vi kan bruge Array.from til at skabe en “rigtig” array fra samlingen, hvis vi vil have array-metoder:

alert( Array.from(document.body.childNodes).filter ); // function
DOM samlinger er kun til at læse fra

DOM samlinger, eller i det hele taget – alle egenskaber til navigation som vi taler om i dette kapitel er kun til at læse fra.

Vi kan ikke erstatte et barn med noget andet ved at tildele childNodes[i] = ....

At ændre DOM kræver andre metoder. Vi vil se dem i næste kapitel.

DOM samlinger er live

Næsten alle DOM samlinger, med enkelte undtagelser, er live. Med andre ord, de afspejler den nuværende tilstand af din DOM.

Hvis vi holder en reference til elem.childNodes, og tilføjer/fjerner noder til DOM, så vises de automatisk i samlingen.

Brug ikke for..in til at loope over samlinger

Samlinger er itererbare ved brug af for..of. Nogle gange prøver folk at bruge for..in til det.

Lad være med det. Et for..in-loop itererer over alle enumerable egenskaber. Og samlinger har nogle “ekstra” sjældent brugte egenskaber, som vi normalt ikke vil have:

<body>
<script>
  // viser 0, 1, length, item, values and more.
  for (let prop in document.body.childNodes) alert(prop);
</script>
</body>

Søskende og forældre (siblings og parents)

Siblings er noder som er børn af samme forælder.

For eksempel så er <head> og <body> søskende her:

<html>
  <head>...</head><body>...</body>
</html>
  • <body> bliver kaldt den “næste” eller “højre” søskende af <head>,
  • <head> bliver kaldt den “forrige” eller “venstre” søskende af <body>.

Den næste søskende er kan hentes med egenskaben nextSibling, og den forrige – med previousSibling.

Forældren er tilgængelig som parentNode.

For eksempel:

// forælder til <body> er <html>
alert( document.body.parentNode === document.documentElement ); // true

// efter <head> kommer <body>
alert( document.head.nextSibling ); // HTMLBodyElement

// før <body> kommer <head>
alert( document.body.previousSibling ); // HTMLHeadElement

Navigation af elementer alene

Egenskaberne til navigation som set ovenfor refererer til alle noder. Vi kan for eksempel med childNodes se både tekstnoder, elementnoder, og endda kommentar noder hvis de eksisterer.

Men i mange tilfælde har vi ikke lyst til at arbejde med tekst- eller kommentar noder. Vi vil gerne manipulere elementnoder, som repræsenterer HTML-tags og udgør strukturen af siden.

Så lad os se flere navigations links, som kun tager element noder i betragtning:

De minder om dem vi har set tidligere, de har bare fået ordet Element tilføjet:

  • children – kun de børn der er elementnoder.
  • firstElementChild, lastElementChild – første og sidste barn der er elementnode.
  • previousElementSibling, nextElementSibling – naboelementer.
  • parentElement – forældre-element.
Why parentElement? Kan en forælder undgå at være et element?

Egenskaben parentElement returnerer “element” forælderen, mens parentNode returnerer “alle typer af node” forælder. Disse egenskaber der normalt de samme: de henter begge forælderen.

Der er dog én undtagelse med document.documentElement:

alert( document.documentElement.parentNode ); // document
alert( document.documentElement.parentElement ); // null

Grunden til dette er at roden document.documentElement (<html>) har document som sin forælder. Men document er ikke en element node så parentNode returner den mens parentElement ikke gør.

Den lille detalje kan være brugbar, hvis vi vil “rejse” op gennem træet fra et vilkårligt element elem til <html>, men ikke til document:

while(elem = elem.parentElement) { // gå op til <html>
  alert( elem );
}

Lad os modificere et af eksemplerne ovenfor: erstat childNodes med children. Nu viser det kun elementerne, og ignorerer tekstnoderne:

<html>
<body>
  <div>Start</div>

  <ul>
    <li>Information</li>
  </ul>

  <div>Slut</div>

  <script>
    for (let elem of document.body.children) {
      alert(elem); // DIV, UL, DIV, SCRIPT
    }
  </script>
  ...
</body>
</html>

Flere links: tabeller

Indtil nu har vi beskrevet de grundlæggende navigationsegenskaber.

Bestemte typer af DOM-elementer kan levere yderligere egenskaber, specifikke for deres type, for nemhedens skyld.

Tabeller er et godt eksempel, og de repræsenterer en særlig vigtig case:

<table> elementet undestøtter (ud over det vi har lært) disse egenskaber:

  • table.rows – en samling af <tr> elementer fra tabellen.
  • table.caption/tHead/tFoot – referencer til elementerne <caption>, <thead>, <tfoot>.
  • table.tBodies – samlingen af <tbody> elementer (kan være mange ifølge standarden, men der vil altid være mindst en – selvom den ikke er i din egen kilde HTML, vil browseren sætte den i DOM).

<thead>, <tfoot>, <tbody> elementer leverer egenskaben rows:

  • tbody.rows – samlingen af <tr> elementer indeni.

<tr>:

  • tr.cells – samlingen af <td> og <th> celler indeni det givne <tr>.
  • tr.sectionRowIndex – positionen (indeks) af det givne <tr> indeni det omkringliggende <thead>/<tbody>/<tfoot>.
  • tr.rowIndex – nummeret på den givne <tr> i tabellen som helhed (inklusiv alle tabelrækker).

<td> and <th>:

  • td.cellIndex – nummeret på cellen indeni den omkransende <tr>.

Et eksempel på brug:

<table id="table">
  <tr>
    <td>en</td><td>to</td>
  </tr>
  <tr>
    <td>tre</td><td>fire</td>
  </tr>
</table>

<script>
  // hent td med "to" (første række, anden kolonne)
  let td = table.rows[0].cells[1];
  td.style.backgroundColor = "red"; // fremhæv den
</script>

Specifikationen: tabular data.

Der er også yderligere muligheder for at navigere formularer. Dem kigger vi på senere når vi skal til at arbejde med formularer.

Opsummering

Givet en hvilken som helst DOM-node, kan vi gå til dens umiddelbare naboer ved at bruge navigationsegenskaber.

Der er to hovedsæt af dem:

  • For alle noder: parentNode, childNodes, firstChild, lastChild, previousSibling, nextSibling.
  • For elementnoder alene: parentElement, children, firstElementChild, lastElementChild, previousElementSibling, nextElementSibling.

Nogle typer af DOM-elementer, f.eks. tabeller, leverer yderligere egenskaber og samlinger til at tilgå deres indhold.

Opgaver

vigtighed: 5

Se på følgende side:

<html>
<body>
  <div>Brugere:</div>
  <ul>
    <li>Lisbeth</li>
    <li>Mikkel</li>
  </ul>
</body>
</html>

For hver af de følgende, giv mindst en måde at tilgå dem:

  • <div> DOM noden?
  • <ul> DOM noden?
  • Den anden <li> (med Mikkel)?

Der er mange måder at gå til det på. Det kunne for eksempel være:

<div> DOM noden:

document.body.firstElementChild
// eller
document.body.children[0]
// eller (den første node er et mellemrum, så vi tager den anden)
document.body.childNodes[1]

<ul> DOM noden:

document.body.lastElementChild
// eller
document.body.children[1]

Den anden <li> (med Mikkel):

// hent <ul>, og derefter hent det sidste barn der er et element
document.body.lastElementChild.lastElementChild
vigtighed: 5

Hvis elem – er en tilfølglig DOM element node…

  • Er det sandt at elem.lastChild.nextSibling altid er null?
  • Er det sandt at elem.children[0].previousSibling altid er null?
  1. Ja, det er sandt. Elementet elem.lastChild er altid det sidste – det har ikke nogen nextSibling.
  2. Nej, det er ikke sandt, fordi elem.children[0] er det første barn mellem elementer. Men der kan eksistere ikke-elementer før det. Så previousSibling kan være en tekstnode.

Bemærk: for begge tilfælde, hvis der ikke er nogen børn, vil der være en fejl.

Hvis der ikke er nogen børn, er elem.lastChild null, så vi kan ikke tilgå elem.lastChild.nextSibling. Og samlingen elem.children er tom (ligesom et tomt array []).

vigtighed: 5

Skriv koden der maler alle diagonale tabelceller røde.

Du skal hente alle diagonale <td> fra <table> og male dem ved hjælp af koden:

// td skal være referencen til tabelcellen
td.style.backgroundColor = 'red';

resulatet skal være dette:

Åbn en sandbox til opgaven.

Vi vil bruge rows og cells egenskaberne til at tilgå diagonale tabelceller.

Åbn løsningen i en sandbox.

Tutorial-oversigt

Kommentarer

læs dette før du kommenterer…
  • Hvis du har forslag til forbedringer - så opret venligst et GitHub-issue eller en pull request i stedet for at kommentere.
  • Hvis du ikke forstår noget i artiklen - så uddyb venligst.
  • For at indsætte få ord kode, brug <code>-taggen, for flere linjer - omslut dem i <pre>-tag, for mere end 10 linjer - brug en sandbox (plnkr, jsbin, codepen…)