Il Document Object Model (o, piรน brevemente, DOM) รจ uno standard ufficiale del W3C attraverso il quale la struttura di un documento (come ad esempio una pagina HTML) รจ rappresentata sotto forma di un modello orientato agli oggetti.
In pratica ogni elemento della struttura del documento รจ rappresentato sotto forma di nodo di un elemento padre creando una sorta di "albero" in cui si creano una serie di ramificazioni. facciamo un esempio partendo da una semplicissima struttura HTML:
<html>
<head>
<title>titolo del documento</title>
</head>
<body>
<h1>titolo H1</h1>
<p>testo testo testo</p>
</body>
</html>
La rappresentazione del DOM di questa pagina sarebbe:
- documento
- head
- title
- titolo del documento (text node)
- title
- body
- h1
- titolo H1 (text node)
- p
- testo testo testo (text node)
- h1
- head
Il DOM e javascript
Attraverso Javascript รจ possibile manipolare il DOM della pagina; ogni elemento della pagina viene rappresentato come un oggetto il quale puรฒ essere manipolato attraverso metodi e proprietร .
Lโoggetto di base per la manipolazione del DOM รจ document il quale rappresenta la radice del documento nel suo complesso (cioรจ la pagina web). Lโoggetto document รจ il genitore di tutti gli altri elementi della pagina web.
Selezionare gli elementi della pagina
Attraverso lโoggetto document รจ possibile accedere a tutti gli elementi della pagina. Per identificare il o gli elementi sui quali agire รจ necessario fare ricorso ad uno di questi metodi:
- getElementByID() โ identifica un solo elemento della pagina attraverso lโattributo ID (univoco);
- getElementByTagName() โ identifica un set di elementi della pagina attraverso lโindicazione dello specifico tag (ad esempio tutti i paragrafi o tutti i link);
- getElementByClassName() โ identifica un set di elementi della pagina attraverso lโindicazione di una specifica classe;
Vediamo qualche esempio:
// identifico uno specifico elemento della pagina
var testo = document.getElementById('articolo');
// all'interno di questo elemento posso selezionare, ad esempio, tutti i link
var links = testo.getElementByTagName('a');
Come potete vedere ho applicato il metodo getElementById allโoggetto document creando, a mia volta, un nuovo oggetto (che ho chiamato "testo"). In seguito ho applicato il metodo getElementByTagName al nuovo oggetto "testo" per identificare tutti i link presenti in quello specifico elemento della pagina.
Modificare lโHTML del documento
Attraverso la proprietร innerHTML posso "scrivere" codice HTML allโinterno di un qualsiasi nodo della pagina. Poco sopra, infatti, abbiamo visto come effettuare la selezione degli elementi e come, una volta selezionati, anche questi si trasformino in oggetti.
A questo punto non resta che applicare la proprietร innerHTML allโoggetto corrispondente al nodo il cui contenuto vogliamo modificare.
var testo = document.getElementById('articolo');
testo.innerHTML = 'Scrivo codice <b>HTML</b>...';
Cosรฌ facendo lโeventuale contenuto dellโelemento selezionato verrร sostituito da quello specificato col metodo innerHTML.
Modificare il valore di un attributo
Nella lezione dedicata agli oggetti di javascript abbiamo accennato al fatto che ogni attributo si "trasforma" in una proprietร dello specifico oggetto element a cui ri riferisce. Ne consegue che abbiamo la possibilitร di manipolare gli attributi a nostro piacimento.
Si supponga, ad esempio, di voler cambiare lโimmagine sorgente (attributo src) di un tag <img>:
document.getElementById('miafoto').src = 'nuovafoto.jpg';
Modificare lo stile CSS di un elemento
Lโattributo style di un oggetto element puรฒ diventare a sua volta un oggetto ed essere manipolato attraverso una serie di proprietร corrispondenti alle proprietร dei fogli di stile. vediamo un esempio:
// imposto il colore rosso per il testo
document.getElementById('articolo').style.color = '#FF0000';
Da notare che in Javascript i nomi di alcune proprietร CSS variano leggermente quando vengono utilizzati sotto forma di proprietร . La proprietร background-image, ad esempio, corrisponde alla proprietร Javascript backgroundImage. In linea di massima possiamo dire che il nome delle proprietร CSS composto da piรน parole separate dal trattino (come ad esempio "border-color") viene trasformato in una stringa unica in cui la parola che segue al trattino (che viene omesso) ha la prima lettera maiuscola (ad esempio "borderColor").
Gestire gli eventi utilizzando il DOM
Attraverso lโutilizzo del DOM รจ anche possibile assegnare un evento ad un dato elemento della pagina. Ad esempio:
document.getElementById('miafoto').onclick = function(){ ... };
In questo caso lโevento Javascript si trasforma in una proprietร dellโoggetto element e, come tale, puรฒ essere settato a piacimento.
Sempre attraverso il DOM รจ possibile creare degli event listener cioรจ dei "rilevatori di eventi" associati a specifici elementi della pagina. Facciamo un esempio:
// assegno una funzione esterna
foto.addEventListener('click', miafunzione);
// definisco internamente al metodo le istruzioni da eseguire
document.getElementById('miafoto').addEventListener('click', function() { alert('...'); });
Eโ possibile associare una molteplicita di event handler (anche dello stesso tipo) a ciascun oggetto. Ad esempio, quindi, possiamo associare diverse funzioni al medesimo evento "click" sul medesimo oggetto con ID "miafoto".
var foto = document.getElementById('miafoto');
foto.addEventListener('click', miafunzione);
foto.addEventListener('click', suafunzione);
foto.addEventListener('click', tuafunzione);
Volendo รจ anche possibile compiere lโoperazione inversa, cioรจ disassociare una funzione da un dato evento su un oggetto. Per farlo si utilizza il metodo removeEventListener in questo modo:
foto.removeEventListener('click', tuafunzione);
Creare un nuovo elemento della pagina
Per aggiungere un nuovo elemento nellโalbero della pagina sarร necessario prima crearlo e poi appenderlo al nodo nel quale o si desidera inserire. Per creare un nuovo elemento nel DOM si utilizza il metodo createElement() specificando, come attributo, che tipo di elemento si desidera creare. Una volta creato lโelemento sarร , ovviamente, vuoto.
Nellโesempio che segue, dopo aver creato un nuovo paragrafo, andremo a riempirlo creando un text-node al suo interno.
// creo il nuovo elemento (un paragrafo)
var nuovo = document.createElement('p');
// creo un nuovo nodo di testo per "riempire" il nuovo elemento
var testo = nuovo.createTextNode('Nuovo testo da inserire');
// appendo il nodo di testo al nuovo elemento
nuovo.appendChild(testo);
// seleziono il nodo nel quale voglio aggiungere il nuovo elemento
var articolo = document.getElementById('articolo');
// ora aggiungo il nuovo elemento al nodo selezionato all'inizio
articolo.appendChild(nuovo);
Utilizzando il metodo appendChild(), il nuovo elemento viene posizionato in fondo allโelemento selezionato. Se non vogliamo che ciรฒ accada ma vogliamo inserire il nuovo elemento in un punto ben preciso abbiamo a disposizione il metodo insertBefore(). Questo metodo richiede due parametri: il primo corrisponde al nuovo elemento da inserire, il secondo corrisponde allโoggetto che identifica il lโelemento prima del quale effettuare lโinserzione.
Si supponga, ad esempio, che il nostro articolo sia cosรฌ strutturato:
<div id="articolo">
<p id="frase1">...</p>
<p id="frase2">...</p>
<p id="frase3">...</p>
</div>
e si supponga di voler inserire il nuovo paragrafo subito dopo il primo. Questo il codice del nostro esempio:
// creo il nuovo elemento (un paragrafo)
var nuovo = document.createElement('p');
// creo un nuovo nodo di testo per "riempire" il nuovo elemento
var testo = nuovo.createTextNode('Nuovo testo da inserire');
// appendo il nodo di testo al nuovo elemento
nuovo.appendChild(testo);
// seleziono il nodo nel quale voglio aggiungere il nuovo elemento
var articolo = document.getElementById('articolo');
// seleziono il sotto-elemento prima del quale voglio inserire quello nuovo
var frase = articolo.getElementById('frase1');
// ora aggiungo il nuovo elemento al nodo selezionato subito prima dell'elemento "frase"
articolo.insertBefore(nuovo,frase);
Se al posto di insertBefore() avessimo utilizzato replaceChild() avremmo sostituito la frase con ID "frase1" con quella generata dinamicamente.
Eliminare un elemento dal DOM
Per eliminare un elemento dallโalbero del DOM si utilizza il metodo removeChild(). Come lascia intuire il nome, viene utilizzato per rimuovere un elemento figlio dellโoggetto selezionato.
Volendo tornare allโesempio visto sopra e supponendo di voler eliminare la frase con id "frase1" avremmo utilizzato il seguente codice:
// seleziono il nodo nel quale voglio lavorare
var articolo = document.getElementById('articolo');
// seleziono il sotto-elemento che desidero cancellare
var frase = articolo.getElementById('frase1');
// ora procedo all'eliminazione
articolo.removeChild(frase);
Una particolaritร del DOM รจ che per rimuovere un elemento dalla pagina รจ sempre necessario conoscere lโelemento genitore. Un "trucchetto" per ovviare a questa procedura รจ offerto da questo codice:
var elimina = document.getElementById('frase1');
elimina.parentNode.removeChild(elimina);
Muoversi tra gli elementi del DOM
Come abbiamo detto il DOM รจ come un albero rappresentato da diversi rami, ogni punto di origine di uno o piรน rami รจ detto nodo. Javascript disponde di diverse proprietร per muoversi allโinterno dei vari nodi di un documento HTML. Questa sono:
- parentNode
- childNodes[indice]
- firstChild
- lastChild
- nextSibling
- previousSibling
Eโ importante sottolineare che nel modello del DOM ogni blocco di testo corrisponde a un noto (Text Node) quindi per accedere, ad esempio, al testo contenuto allโinterno di una tag <p> sarร necessario far riferimento ad un ulteriore nodo (il nodo di testo, appunto) e poi applicare la proprietร nodeValue:
var testo = document.getElementById('frase1').firstChild.nodeValue;
In realtร , per raggiungere il nostro scopo, avremmo potuto scrivere piรน semplicemente:
var testo = document.getElementById('frase1').innerHTML;
Tuttavia era necessario sottolineare come, nel DOM, i blocchi di testo siano qualificati come nodi a se stanti.
parentNode
la proprietร parentNode consente di accedere al nodo genitore dellโoggetto element corrente.
Abbiamo giร visto questa proprietร allโopera poco sopra, nellโultimo esempio relativo allโeliminazione di un elemento dal DOM (cui vi invito a fare riferimento).
firstChild e lastChild
Queste tre proprietร consentono di accedere, rispettivamente, al primo nodo e allโultimo elemento figlio dellโoggetto element corrente.
childNodes
la proprietร childNodes consente di accedere ad un determinato nodo figlio specificandone lโindice numerico (ricordiamoci che la numerazione degli indici parte da 0 e NON da 1!).
In sostanza possiamo dire che childNodes[0] รจ lโequivalente di firstChild.
nextSibling e previousSibling
Queste due proprietร consentono di muoversi tra i nodi "fratelli" e piรน precisamente consento di accedere a quello precedente e quello successivo.
La radice del documento
Per accedere alla radice della nostra pagina HTML possiamo utilizzare la proprietร documentElement dellโoggetto document.
Se desideriamo selezionare solo il corpo del documento, invece, possiamo utilizzare semplicemente la proprietร body.
var radice = document.documentElement;
var corpo = document.body;