DOM: Selezionare Elementi
Impara a selezionare e accedere agli elementi HTML con JavaScript
🌳 Cos’è il DOM?
Il DOM (Document Object Model) è la rappresentazione ad albero di una pagina web.
JavaScript può accedere e modificare tutti gli elementi HTML attraverso il DOM!
💡 Come Funziona
Quando il browser carica una pagina HTML, crea un modello a oggetti del documento.
Ogni elemento HTML diventa un “nodo” che JavaScript può leggere, modificare, aggiungere o eliminare.
document (root)
└─ html
├─ head
│ ├─ title
│ └─ meta
└─ body
├─ header
│ └─ h1
├─ main
│ ├─ p
│ └─ div
└─ footer
- ✅ querySelector() – Selettore CSS moderno (⭐ CONSIGLIATO)
- ✅ getElementById() – Seleziona per ID
- ✅ getElementsByClassName() – Seleziona per classe
- ✅ getElementsByTagName() – Seleziona per tag
- ✅ Navigazione DOM – Parent, children, siblings
- ✅ Best Practices – Quale metodo usare quando
⭐ querySelector() e querySelectorAll()
I metodi querySelector() sono i più moderni e versatili.
Usano la stessa sintassi dei selettori CSS!
Restituisce il PRIMO elemento che corrisponde al selettore.
<!DOCTYPE html>
<html>
<head>
<title>Demo DOM</title>
</head>
<body>
<h1 id="titolo">Benvenuto!</h1>
<p class="testo">Primo paragrafo</p>
<p class="testo">Secondo paragrafo</p>
<button id="btn">Clicca</button>
<div class="container">
<span class="highlight">Importante</span>
</div>
</body>
</html>
// Seleziona per ID (con #)
const titolo = document.querySelector('#titolo');
console.log(titolo); // <h1 id="titolo">Benvenuto!</h1>
// Seleziona per classe (con .)
const paragrafo = document.querySelector('.testo');
console.log(paragrafo); // Primo <p> con classe "testo"
// Seleziona per tag
const button = document.querySelector('button');
console.log(button); // <button id="btn">Clicca</button>
// Selettori complessi (come CSS!)
const span = document.querySelector('.container .highlight');
console.log(span); // <span class="highlight">Importante</span>
// Selettori attributo
const btnById = document.querySelector('[id="btn"]');
// Pseudo-classi
const primoP = document.querySelector('p:first-child');
const ultimoP = document.querySelector('p:last-child');
Restituisce una NodeList con TUTTI gli elementi corrispondenti.
// Seleziona TUTTI i paragrafi con classe "testo"
const tuttiParagrafi = document.querySelectorAll('.testo');
console.log(tuttiParagrafi); // NodeList(2) [p.testo, p.testo]
console.log(tuttiParagrafi.length); // 2
// Itera con forEach
tuttiParagrafi.forEach((p, indice) => {
console.log(`Paragrafo ${indice + 1}: ${p.textContent}`);
});
// Output:
// Paragrafo 1: Primo paragrafo
// Paragrafo 2: Secondo paragrafo
// Converti in array per usare metodi array
const arrayP = Array.from(tuttiParagrafi);
// Oppure con spread
const arrayP2 = [...tuttiParagrafi];
const testi = arrayP.map(p => p.textContent);
console.log(testi); // ["Primo paragrafo", "Secondo paragrafo"]
// Selettori multipli (con virgola)
const elementi = document.querySelectorAll('h1, p, button');
console.log(elementi.length); // 4 (1 h1 + 2 p + 1 button)
// Tutti gli elementi con data attribute
const conData = document.querySelectorAll('[data-id]');
- 🌟 Sintassi CSS familiare
- 🌟 Selettori complessi supportati
- 🌟 Metodo moderno (ES5+)
- 🌟 Più flessibile degli altri metodi
- ⭐ QUESTO È IL METODO CONSIGLIATO!
🆔 getElementById()
Seleziona un elemento tramite il suo ID univoco.
Metodo classico, veloce ma limitato.
<h1 id="titolo-principale">Benvenuto</h1> <div id="container">Contenuto</div> <button id="btn-submit">Invia</button>
// Sintassi: document.getElementById('id')
// NOTA: NON usa il simbolo #
const titolo = document.getElementById('titolo-principale');
console.log(titolo); // <h1 id="titolo-principale">Benvenuto</h1>
const container = document.getElementById('container');
console.log(container.textContent); // "Contenuto"
const button = document.getElementById('btn-submit');
console.log(button);
// Se l'ID non esiste, restituisce null
const nonEsiste = document.getElementById('fake-id');
console.log(nonEsiste); // null
// Controlla sempre prima di usare
if (titolo) {
console.log(titolo.textContent);
} else {
console.log("Elemento non trovato");
}
// getElementById - veloce ma limitato
const el1 = document.getElementById('mio-id');
// querySelector - più flessibile
const el2 = document.querySelector('#mio-id');
// Entrambi selezionano lo stesso elemento!
// querySelector è più moderno e versatile ✅
📦 getElementsByClassName()
Seleziona TUTTI gli elementi con una specifica classe.
Restituisce una HTMLCollection live.
<p class="testo">Primo</p> <p class="testo">Secondo</p> <p class="testo highlight">Terzo</p> <div class="box">Box</div>
// Sintassi: document.getElementsByClassName('classe')
// NOTA: NON usa il punto .
const paragrafi = document.getElementsByClassName('testo');
console.log(paragrafi); // HTMLCollection(3) [p.testo, p.testo, p.testo]
console.log(paragrafi.length); // 3
// Accesso per indice
console.log(paragrafi[0].textContent); // "Primo"
console.log(paragrafi[1].textContent); // "Secondo"
// ⚠️ HTMLCollection NON ha forEach!
// paragrafi.forEach(...); // ERRORE!
// ✅ Converti in array prima
const arrayP = Array.from(paragrafi);
arrayP.forEach((p, i) => {
console.log(`${i + 1}. ${p.textContent}`);
});
// Oppure usa for classico
for (let i = 0; i < paragrafi.length; i++) {
console.log(paragrafi[i].textContent);
}
// for...of funziona!
for (let p of paragrafi) {
console.log(p.textContent);
}
La collection si aggiorna automaticamente quando il DOM cambia!
const boxes = document.getElementsByClassName('box');
console.log(boxes.length); // 1
// Aggiungi nuova box al DOM
const nuovaBox = document.createElement('div');
nuovaBox.className = 'box';
document.body.appendChild(nuovaBox);
console.log(boxes.length); // 2 (aggiornato automaticamente!)
// querySelector invece NON è live (static)
🏷️ getElementsByTagName()
Seleziona TUTTI gli elementi di un certo tag HTML.
Restituisce una HTMLCollection live.
// Tutti i paragrafi
const paragrafi = document.getElementsByTagName('p');
console.log(paragrafi.length);
// Tutti i div
const divs = document.getElementsByTagName('div');
// Tutti i link
const links = document.getElementsByTagName('a');
// Tutte le immagini
const immagini = document.getElementsByTagName('img');
// Itera (converti in array)
const arrayP = Array.from(paragrafi);
arrayP.forEach((p, i) => {
console.log(`P ${i + 1}: ${p.textContent}`);
});
// TUTTI gli elementi (*)
const tuttiGliElementi = document.getElementsByTagName('*');
console.log(`Totale elementi: ${tuttiGliElementi.length}`);
Usa getElementsByTagName() quando vuoi:
- Selezionare TUTTI gli elementi di un tipo
- Contare elementi (es: quante immagini ci sono?)
- Applicare stile a tutti i tag di un tipo
⚠️ Ma querySelectorAll('p') è più moderno e fa lo stesso!
🧭 Navigazione DOM
Una volta selezionato un elemento, puoi navigare verso i suoi parenti, figli e fratelli!
<div id="container">
<h2 id="titolo">Titolo</h2>
<p id="paragrafo1">Primo paragrafo</p>
<p id="paragrafo2">Secondo paragrafo</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div>
const paragrafo1 = document.querySelector('#paragrafo1');
// PARENT - Genitore
const parent = paragrafo1.parentElement;
console.log(parent); // <div id="container">
// CHILDREN - Figli diretti
const container = document.querySelector('#container');
console.log(container.children); // HTMLCollection dei figli
console.log(container.children.length); // 4
// Primo e ultimo figlio
console.log(container.firstElementChild); // <h2>
console.log(container.lastElementChild); // <ul>
// SIBLINGS - Fratelli
const primoP = document.querySelector('#paragrafo1');
// Fratello successivo
const next = primoP.nextElementSibling;
console.log(next); // <p id="paragrafo2">
// Fratello precedente
const secondoP = document.querySelector('#paragrafo2');
const prev = secondoP.previousElementSibling;
console.log(prev); // <p id="paragrafo1">
const elemento = document.querySelector('#paragrafo1');
// PARENT
elemento.parentElement // Genitore (Element)
elemento.parentNode // Genitore (Node)
// CHILDREN
elemento.children // HTMLCollection di figli (solo Element)
elemento.childNodes // NodeList di tutti i nodi (include testo)
elemento.firstElementChild // Primo figlio Element
elemento.lastElementChild // Ultimo figlio Element
elemento.childElementCount // Numero di figli
// SIBLINGS
elemento.nextElementSibling // Fratello successivo
elemento.previousElementSibling // Fratello precedente
// Verifica se ha figli
if (elemento.children.length > 0) {
console.log("Ha figli");
}
// Verifica se ha parent
if (elemento.parentElement) {
console.log("Ha un genitore");
}
Risale l'albero DOM fino a trovare un elemento che corrisponde al selettore.
<div class="container">
<div class="card">
<button id="btn">Clicca</button>
</div>
</div>
// JavaScript
const button = document.querySelector('#btn');
// Trova il .card genitore (più vicino)
const card = button.closest('.card');
console.log(card);
// Trova il .container genitore
const container = button.closest('.container');
console.log(container);
// Uso pratico: event delegation
button.addEventListener('click', (e) => {
const card = e.target.closest('.card');
if (card) {
console.log("Hai cliccato nella card!");
}
});
| Relazione | Proprietà | Descrizione |
|---|---|---|
| ⬆️ Genitore | parentElement |
Elemento genitore diretto |
| ⬇️ Figli | children |
Tutti i figli diretti (HTMLCollection) |
| ⬇️ Primo figlio | firstElementChild |
Primo figlio Element |
| ⬇️ Ultimo figlio | lastElementChild |
Ultimo figlio Element |
| ➡️ Fratello dopo | nextElementSibling |
Fratello successivo |
| ⬅️ Fratello prima | previousElementSibling |
Fratello precedente |
📊 Confronto Metodi di Selezione
| Metodo | Restituisce | Live? | Quando Usare |
|---|---|---|---|
querySelector() |
1 Element o null | ❌ No | ⭐ Selettore CSS (CONSIGLIATO) |
querySelectorAll() |
NodeList (static) | ❌ No | ⭐ Tutti con selettore CSS |
getElementById() |
1 Element o null | ❌ No | Solo ID (veloce ma limitato) |
getElementsByClassName() |
HTMLCollection | ✅ Sì | Classe (meglio querySelector) |
getElementsByTagName() |
HTMLCollection | ✅ Sì | Tag (meglio querySelector) |
🌟 Usa querySelector() e querySelectorAll() come default!
- ✅ Sintassi CSS familiare
- ✅ Più flessibile e potente
- ✅ Standard moderno
- ✅ NodeList ha forEach()
- ⚠️ Gli altri metodi sono legacy ma ancora funzionanti
🚀 Esempio Completo: Task List Navigator
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<title>Task List</title>
<style>
.task { padding: 10px; margin: 5px 0; border: 1px solid #ddd; }
.task.completed { background: #d4edda; text-decoration: line-through; }
.task.priority-high { border-left: 4px solid #dc3545; }
.task.priority-medium { border-left: 4px solid #ffc107; }
.task.priority-low { border-left: 4px solid #28a745; }
</style>
</head>
<body>
<div id="app">
<h1>Task List</h1>
<div class="controls">
<button id="btn-show-all">Mostra Tutti</button>
<button id="btn-show-completed">Solo Completati</button>
<button id="btn-show-pending">Solo Pendenti</button>
</div>
<div id="tasks-container">
<div class="task priority-high" data-id="1">
<input type="checkbox" class="task-checkbox">
<span class="task-title">Studiare JavaScript</span>
<span class="task-priority">Alta</span>
</div>
<div class="task priority-medium completed" data-id="2">
<input type="checkbox" class="task-checkbox" checked>
<span class="task-title">Fare la spesa</span>
<span class="task-priority">Media</span>
</div>
<div class="task priority-low" data-id="3">
<input type="checkbox" class="task-checkbox">
<span class="task-title">Chiamare Mario</span>
<span class="task-priority">Bassa</span>
</div>
<div class="task priority-high" data-id="4">
<input type="checkbox" class="task-checkbox">
<span class="task-title">Finire progetto</span>
<span class="task-priority">Alta</span>
</div>
</div>
<div id="stats"></div>
</div>
<script src="script.js"></script>
</body>
</html>
// === SELEZIONE ELEMENTI ===
// Container principale
const app = document.querySelector('#app');
const tasksContainer = document.querySelector('#tasks-container');
const statsDiv = document.querySelector('#stats');
// Bottoni
const btnShowAll = document.querySelector('#btn-show-all');
const btnShowCompleted = document.querySelector('#btn-show-completed');
const btnShowPending = document.querySelector('#btn-show-pending');
// Tasks
const tuttiTasks = document.querySelectorAll('.task');
console.log(`Totale tasks: ${tuttiTasks.length}`);
// === FUNZIONI UTILITY ===
// Ottieni tutti i task (freschi dal DOM)
function getTasks() {
return document.querySelectorAll('.task');
}
// Ottieni task completati
function getCompletedTasks() {
return document.querySelectorAll('.task.completed');
}
// Ottieni task pendenti
function getPendingTasks() {
const tutti = getTasks();
return Array.from(tutti).filter(task => {
return !task.classList.contains('completed');
});
}
// Ottieni task per priorità
function getTasksByPriority(priority) {
return document.querySelectorAll(`.task.priority-${priority}`);
}
// === STATISTICHE ===
function updateStats() {
const tutti = getTasks();
const completati = getCompletedTasks();
const pendenti = getPendingTasks();
const alte = getTasksByPriority('high');
const medie = getTasksByPriority('medium');
const basse = getTasksByPriority('low');
statsDiv.innerHTML = `
<h3>📊 Statistiche</h3>
<p>Totale: ${tutti.length}</p>
<p>Completati: ${completati.length}</p>
<p>Pendenti: ${pendenti.length}</p>
<hr>
<p>Priorità Alta: ${alte.length}</p>
<p>Priorità Media: ${medie.length}</p>
<p>Priorità Bassa: ${basse.length}</p>
`;
}
// === FILTRI ===
function showAll() {
getTasks().forEach(task => {
task.style.display = 'block';
});
}
function showCompleted() {
getTasks().forEach(task => {
if (task.classList.contains('completed')) {
task.style.display = 'block';
} else {
task.style.display = 'none';
}
});
}
function showPending() {
getTasks().forEach(task => {
if (!task.classList.contains('completed')) {
task.style.display = 'block';
} else {
task.style.display = 'none';
}
});
}
// === EVENT LISTENERS ===
btnShowAll.addEventListener('click', showAll);
btnShowCompleted.addEventListener('click', showCompleted);
btnShowPending.addEventListener('click', showPending);
// === NAVIGAZIONE DOM ===
// Analizza struttura
console.log("=== ANALISI DOM ===");
const primoTask = document.querySelector('.task');
console.log("Primo task:", primoTask);
// Parent
console.log("Parent:", primoTask.parentElement);
// Siblings
const secondoTask = primoTask.nextElementSibling;
console.log("Secondo task:", secondoTask);
// Children
const checkbox = primoTask.querySelector('.task-checkbox');
const title = primoTask.querySelector('.task-title');
const priority = primoTask.querySelector('.task-priority');
console.log("Checkbox:", checkbox);
console.log("Titolo:", title.textContent);
console.log("Priorità:", priority.textContent);
// === INFO DETTAGLIATE OGNI TASK ===
console.log("\n=== DETTAGLI TASKS ===");
getTasks().forEach((task, indice) => {
const id = task.getAttribute('data-id');
const title = task.querySelector('.task-title').textContent;
const isCompleted = task.classList.contains('completed');
const priority = task.className.match(/priority-(\w+)/)[1];
console.log(`Task ${indice + 1}:`);
console.log(` ID: ${id}`);
console.log(` Titolo: ${title}`);
console.log(` Completato: ${isCompleted ? 'Sì' : 'No'}`);
console.log(` Priorità: ${priority}`);
console.log('');
});
// === INIZIALIZZAZIONE ===
updateStats();
// Output console:
// Totale tasks: 4
// === ANALISI DOM ===
// Primo task: <div class="task priority-high"...
// Parent: <div id="tasks-container">
// Secondo task: <div class="task priority-medium completed"...
// Checkbox: <input type="checkbox"...
// Titolo: Studiare JavaScript
// Priorità: Alta
//
// === DETTAGLI TASKS ===
// Task 1:
// ID: 1
// Titolo: Studiare JavaScript
// Completato: No
// Priorità: high
//
// Task 2:
// ID: 2
// Titolo: Fare la spesa
// Completato: Sì
// Priorità: medium
// ... (continua)
querySelector()- Selezione singoli elementiquerySelectorAll()- Selezione multipla- Selettori complessi -
.task.completed,.priority-high - Data attributes -
data-id - Navigazione DOM - parent, children, siblings
- classList - Verifica classi
- Array.from() - Converti NodeList
✅ Best Practices
// ✅ CONSIGLIATO
const elemento = document.querySelector('#mio-id');
const tutti = document.querySelectorAll('.mia-classe');
// ❌ EVITA (a meno che non serva specificatamente)
const elemento = document.getElementById('mio-id');
const tutti = document.getElementsByClassName('mia-classe');
Evita di selezionare lo stesso elemento più volte.
// ❌ MALE - Seleziona ogni volta
document.querySelector('#btn').addEventListener('click', () => {
document.querySelector('#output').textContent = "Cliccato!";
});
document.querySelector('#btn').style.color = 'blue';
// ✅ BENE - Cachea la selezione
const btn = document.querySelector('#btn');
const output = document.querySelector('#output');
btn.addEventListener('click', () => {
output.textContent = "Cliccato!";
});
btn.style.color = 'blue';
// ❌ PERICOLOSO - Può causare errori
const elemento = document.querySelector('#potrebbe-non-esistere');
elemento.textContent = "Test"; // TypeError se null!
// ✅ SICURO - Controlla prima
const elemento = document.querySelector('#potrebbe-non-esistere');
if (elemento) {
elemento.textContent = "Test";
} else {
console.log("Elemento non trovato");
}
// ✅ SICURO - Optional chaining (ES2020)
const elemento = document.querySelector('#potrebbe-non-esistere');
elemento?.classList.add('active'); // Non fa nulla se null
Cerca dentro un elemento specifico invece di tutto il document.
// ❌ LENTO - Cerca in tutto il documento
const button = document.querySelector('.container .card .button');
// ✅ VELOCE - Cerca in scope ridotto
const container = document.querySelector('.container');
const card = container.querySelector('.card');
const button = card.querySelector('.button');
// Oppure
const button = document.querySelector('.container')
.querySelector('.card')
.querySelector('.button');
- ⭐ CONSIGLIATO
- Sintassi CSS
- Primo elemento
- ⭐ CONSIGLIATO
- Tutti gli elementi
- NodeList con forEach
- parentElement
- children
- nextElementSibling
- Usa querySelector
- Cachea selezioni
- Controlla esistenza