Salta el contingut

Model d'objectes del document (DOM)

Què és el DOM

El DOM (Document Object Model) és un model d'objectes que representa les pàgines HTML en forma d'arbre amb diferents nodes.

El DOM defineix:

  • cada element HTML com un objecte
  • les propietats de cada element HTML
  • els mètodes per accedir als elements HTML
  • els esdeveniments de cada element HTML

A través del DOM es pot referenciar i manipular qualsevol element del document HTML:

  • modificar els elements de la pàgina
  • modificar els atributs i l'estil dels elements
  • afegir i eliminar elements i atributs
  • crear i modificar esdeveniments

Quan es carrega una pàgina HTML, el navegador crea l'arbre DOM de la pàgina.
Podem manipular qualsevol node del DOM utilitzant JavaScript i les alteracions es reflectiran immediatament a la pàgina HTML (i a la inversa passarà el mateix).

Important!

El DOM es crea en el moment en què la pàgina ha finalitzat de carregar tot el contingut, per tant hem d'assegurar-nos de no intentar accedir-hi abans.

img

L'objecte document representa tota la pàgina i és el propietari de tota la resta d'objectes.

Per accedir a objectes de la pàgina HTML sempre haurem de partir inicialment de l'objecte document.

A través dels seus mètodes associats podem:

Localitzar elements HTML

getElementById

Localitza un element pel seu id i el retorna si el troba.
Altrament, retorna null.

var element = document.getElementById("titol");

getElementById és un mètode d'ús exclusiu per l'objecte document

A diferencia d'altres mètodes del DOM, getElementById només es pot invocar com a mètode de l'objecte global document, i donarà error si s'utilitza com a mètode d'un altre objecte del DOM. Això és així perquè els valors de id han de ser únics al document, i per tant no hi ha necessitat de buscar-los dins d'un element concret.

Atenció

Cal sempre evitar tenir elements amb el mateix id
Si més d'un element de la pàgina té assignat el mateix id, se'ns retornarà el primer que localitzi en recòrrer l'estructura del DOM.

getElementsByTagName

Localitza elements segons la seva etiqueta HTML.
Retorna una llista de nodes en forma d'objecte HTMLCollection.

Atenció

El tipus de dades HTMLCollection és un un tipus viu, de manera que s'actualitza automàticament quan el document canvia.

// Cerquem tots els elements de tipus "div" del document

var llista = document.getElementsByTagName("div");

Podem recórrer una llista de nodes de la mateixa manera que ho fariem amb un array, utilitzant una iteració for:

for ( let i = 0; i  < llista.length; i++ ) {
    var element = llista[ i ]
    ///
}

o amb una iteració for...of, que ens retornarà els valors de la lista seqüencialment:

for (var element of llista) {
  ///
}

Podem cercar elements a una branca concreta del DOM enlloc de tot el document.

Per fer-ho, invoquem el mètode sobre l'element inicial de la cerca, i aquesta es farà només dins dels nodes que hi estiguin continguts.

// Cerquem els elements de tipus "div" que es troben dins de
// l'element amb id "inici", però no la resta de divs del document

var origen = document.getElementById("inici")
var llista = origen.getElementsByTagName("div")

// O bé sense variable auxiliar

var llista = document.getElementById("inici").getElementsByTagName("div")

getElementsByClassName

Localitza els elements segons seu nom de classe CSS, troba tots aquells que tinguin la classe indicada dins la seva llista de classes.
Retorna una llista de nodes en forma d'objecte HTMLCollection.

Atenció

El tipus de dades HTMLCollection és un un tipus viu, de manera que s'actualitza automàticament quan el document canvia.

// Cerquem tots els elements HTML que tinguin la classe "e1",
// també si tenen altres classes simultàniament

var llista = document.getElementsByClassName("e1");

querySelector

Localitza un element segons els seus selectors amb sintaxi CSS.

Retorna el primer element dins del DOM que compleixi la condició, i si no en troba cap retorna null.

// Cerquem el primer element de tipus "p" que tingui la classe "titol"

var element = document.querySelector("p.titol");

querySelectorAll

Localitza llistes d'elements segons els seus selectors amb sintaxi CSS.

Retorna un objecte HTMLCollection amb la llista d'elements que compleixin la condició (tots els elements <p> amb class="títol" del document).

// Cerquem tots els elements del document que siguin
// de tipus "p" i que tinguin la classe "titol"

var element = document.querySelectorAll("p.titol");

Modificar elements HTML

Llegir i modificar el contingut

Podem consultar o modificar el contingut d'un element HTML a través de les propietats innerHTML, innerText i textContent.

  • innerHTML escriu i retorna el contingut mantenint les etiquetes HTML i les seqüències de caràcters especials (també les unicode).

  • innerText no fa cap conversió i escriu i retorna només el contingut de text de l'element HTML tal i com apareix després d'aplicar conversions HTML d'espais i salts de línia i els estils de l'element.

  • textContent escriu i retorna un resultat similar al de innerText però sense convertir els espais i salts de línia del text.

Escriptura

Resultat visible a la pàgina
element.innerHTML = "<b>HOLA</b>" HOLA
element.innerText = "<b>HOLA</b>" <b>HOLA</b>
element.textContent = "<b>HOLA</b>" <b>HOLA</b>

Lectura

<div id="element">Text en <b>negreta</b> i     <i>cursiva</i></div>
Valor retornat
element.innerHTML Text en <b>negreta</b> i     <i>cursiva</i>
element.innerText Text en negreta i cursiva
element.textContent Text en negreta i     cursiva

Canviar el valor d'un atribut

Podem fer-ho assignant-li directament un valor al nom de l'atribut de l'element:

document.getElementById( id ).nom_atribut = nou_valor

o amb el mètode setAttribute, passant-li com a paràmetres el nom de l'atribut i el seu valor.
Un avantatge de fer-ho així és que el nom de l'atribut a modificar pot ser una variable:

document.getElementById( id ).setAttribute( "nom_atribut", "nou_valor" )

var atr = "nom_atribut"
document.getElementById( id ).setAttribute( atr, "nou_valor" )

Canviar el valor d'una propietat d'estil

Podem fer-ho assignant-li directament un valor al nom de la propietat CSS a través de l'atribut style de l'element:

document.getElementById( id ).style.nom_propietat = nou_valor

Per utilitzar els noms de les propietats CSS amb JavaScript cal seguir aquestes regles:

  • si la propietat conté més d'una paraula separades per guionets, es converteix a camelCase
  • si la propietat és una sola paraula no es fa cap canvi
  • excepció: la propietat float es converteix en cssFloat per ser paraula reservada

Exemples:

CSS JavaScript
width width
height height
float cssFloat
background-color backgroundColor
border-bottom-width borderBottomWidth
z-index zIndex
document.getElementById( id ).style.border-color = "red" // ERROR
document.getElementById( id ).style.borderColor  = "red" // Correcte

També podem assignar el nou valor de CSS a la propietat style amb la notació de claus ([ ]).
Un avantatge de fer-ho així és que el nom de l'atribut CSS a modificar pot ser dinàmic:

document.getElementById( id ).style[ "nom_propietat" ] = nou_valor

var prop = "nom_propietat"
document.getElementById( id ).style[ prop ] = nou_valor

Si utilitzem aquesta sintaxi no cal fer cap conversió al nom de la propietat CSS i la podem utilitzar tal i com l'escriuriem en un full d'estils:

document.getElementById( id ).style[ "border-color" ] = "red" // Correcte

Operar sobre la llista de classes d'un element (classList)

Podem actuar sobre la llista de classes d'un element HTML de diferents formes i el resultat es reflectirà immediatament en pantalla.
Per fer-ho utilitzem mètodes de la propietat classList.

add()

Afegeix una o diverses classes a l'element:

document.getElementById( id ).classList.add ( "nom_classe" )
document.getElementById( id ).classList.add ( "classe_1", "classe_2")

remove()

Elimina una o diverses classes de l'element:

document.getElementById( id ).classList.remove ( "nom_classe" )
document.getElementById( id ).classList.remove ( "classe_1", "classe_2")

Nota

Intentar eliminar una classe que no existeix o que l'element no té NO provoca un error.

toggle()

Alterna la presència d'una la classe dins de la llista de classes de l'element.
Si la classe existeix, s'elimina i retorna false. Altrament s'afegeix i retorna true.

document.getElementById( "boto" ).onclick = function ()
{
    document.getElementById( "quadrat" ).classList.toggle( "vermell" )
}

contains()

Retorna un booleà indicant si la classe existeix o no dins de la llista de classes de l'element.

document.getElementById( id ).classList.contains ( "nom_classe" )

replace()

Substitueix una classe existent per una de nova.

document.getElementById( id ).classList.replace ( "classe", "classe_nova" )

Assignar esdeveniments

Podem fer-ho amb el nom de l'esdeveniment o amb addEventListener:

document.getElementById("element").onclick = function() {
    ///
};

document.getElementById("element").addEventListener( "click", function() {
    ///
} );

Afegir i esborrar elements

Segons l'especificació del DOM, tot el que hi ha en un document HTML es representa com un node d'un tipus concret:

  • el document sencer és el node de tipus document
  • cada element HTML és un node de tipus element
  • el text que hi ha dins dels elements HTML són nodes de tipus text
  • cada atribut d'un element és un node de tipus atribut
  • tots els comentaris són nodes de tipus comentari

Relació entre nodes

Els nodes estan relacionats jeràrquicament:

  • el node inicial s'anomena node arrel
  • cada node té exactament un sol pare, excepte el node arrel que no en té cap
  • un node pot tenir qualsevol nombre de nodes fills
  • els nodes germans (siblings) són aquells que tenen el mateix pare

Podem utilitzar les següents propietats per navegar entre nodes amb JavaScript:

Crear nous elements HTML (nodes)

Per afegir elements al DOM cal fer-ho en dues passes:
1. Crear el node del tipus d'element que volem, utilitzant el mètode createElement()
2. Associar-lo com a fill d'un element ja existent amb appendChild() o insertBefore()

Afegir un element amb appendChild()

El mètode appendChild afegeix un node nou com a últim element fill dins d'un altre node.

<button id="btn">appendChild()</button>

<div id="div1">
    <p id="p1">Primer paràgraf</p>
    <p id="p2">Segon paràgraf</p>
</div>

<script>
    document.getElementById("btn").onclick = function () {
        var nou = document.createElement("p");
        nou.innerHTML = "Paràgraf nou";
        nou.style.color = "red";
        document.getElementById("div1").appendChild(nou);
    }
</script>

Afegir un element amb insertBefore()

El mètode insertBefore afegeix un node nou com a element fill situant-lo just davant d'un altre node ja existent.

<button id="btn">insertBefore()</button>

<div id="div1">
    <p id="p1">Primer paràgraf</p>
    <p id="p2">Segon paràgraf</p>
</div>

<script>
    document.getElementById("btn").onclick = function () {
        var nou = document.createElement("p");
        nou.innerHTML = "Paràgraf nou";
        nou.style.color = "red";
        posicio = document.getElementById("p2");
        document.getElementById("div1").insertBefore(nou, posicio);
    }
</script>

Moure un element

Si utilitzem appendChild o insertBefore sobre un node ja existent enlloc d'un de nou, el desplaçarà a la nova posició.
Per indicar el node a moure, el passem com a paràmetre del mètode utilitzat.

<button id="btn">moure element</button>

<div id="div1">
    <p id="p1">Primer paràgraf</p>
    <p id="p2">Segon paràgraf</p>
</div>
<hr>
<div id="div2">
    <p id="p3">Tercer paràgraf</p>
    <p id="p4">Quart paràgraf</p>
</div>

<script>
    document.getElementById("btn").onclick = function () {
        canvi = document.getElementById("p4");
        document.getElementById("div1").appendChild(canvi);
    }
</script>

Eliminar elements HTML existents

Podem eliminar un element invocant el mètode remove del mateix element.

Sintaxi

node.remove()

<button id="btn">remove()</button>

<div id="div1">
    <p id="p1">Primer paràgraf</p>
    <p id="p2">Segon paràgraf</p>
</div>

<script>
    document.getElementById("btn").onclick = function () {
        document.getElementById("p2").remove();
    }
</script>

També podem eliminar un element del DOM és a través del seu node pare utilitzant el mètode removeChild.

Sintaxi

node.removeChild( node )

Retorna el node eliminat, o null si no existeix

<button id="btn">removeChild()</button>

<div id="div1">
    <p id="p1">Primer paràgraf</p>
    <p id="p2">Segon paràgraf</p>
</div>

<script>
    document.getElementById("btn").onclick = function () {
        eliminar = document.getElementById("p2");
        document.getElementById("div1").removeChild(eliminar);
    }
</script>

Substituir elements HTML

Amb el mètode replaceChild podem reemplaçar un node fill d'un element per un altre node.

<button id="btn">replaceChild()</button>

<div id="div1">
    <p id="p1">Primer paràgraf</p>
    <p id="p2">Segon paràgraf</p>
</div>

<script>
    document.getElementById("btn").onclick = function () {
        var nou = document.createElement("p");
        nou.innerHTML = "Paràgraf nou";
        substituir = document.getElementById("p1");
        document.getElementById("div1").replaceChild(nou, substituir);
    }
</script>

Atenció

Si el node nou és un element ja existent al DOM enlloc d'un node nou, es desplaçarà de la seva nova posició i substituirà al node vell.

Exemples

Esborrar elements segons la seva classe CSS

Crear i destruir elements dinàmicament amb el DOM

Crear elements a partir de classes (estil Bootstrap)

Paginador simple per galeria d'imatges

The Matrix

Boles que reboten (versió amb DIV)

Boles que reboten (versió amb CANVAS)

Projecte 1 - Paginador

Projecte 1 - Filtre

Projecte 1 - Formulari dinàmic