Tecniche di Manipolazione del DOM in JavaScript
Impara le tecniche di manipolazione del DOM in JavaScript: crea, inserisci, sostituisci e rimuovi elementi, poi ottimizza con batching, frammenti e clonazione dei nodi.
La manipolazione del DOM (Document Object Model) è un aspetto fondamentale dello sviluppo web che consente di creare pagine dinamiche e interattive modificando la struttura, il contenuto e lo stile del documento tramite JavaScript. Questa guida inizia con le tecniche di base per creare, inserire, sostituire e rimuovere elementi, per poi passare alle best practice e alle ottimizzazioni delle prestazioni — batching, frammenti di documento e clonazione dei nodi — che mantengono veloci queste modifiche.
Se non hai ancora selezionato un elemento, inizia con la selezione degli elementi DOM. Per comprendere l'albero che stai modificando, consulta la comprensione dei nodi DOM.
Tecniche di Manipolazione di Base
Ogni modifica al DOM rientra in una di quattro categorie: creazione di nodi, inserimento, sostituzione o rimozione.
Creazione di Elementi
Usa document.createElement() per costruire un elemento in memoria, poi imposta il suo contenuto e i suoi attributi prima di inserirlo nella pagina. Un nodo che crei non è visibile finché non lo colleghi al documento.
const card = document.createElement('div');
card.className = 'card';
card.textContent = 'Hello, DOM!';
card.setAttribute('data-role', 'greeting');
console.log(card.outerHTML);
// <div class="card" data-role="greeting">Hello, DOM!</div>Preferisci textContent rispetto a innerHTML quando inserisci testo semplice — è più veloce ed evita il rischio di sicurezza legato all'iniezione di HTML non sanificato.
Inserimento di Elementi
Una volta che un elemento esiste, collegalo con uno di questi metodi:
parent.append(node)— aggiunge il nodo come ultimo figlio (accetta anche stringhe semplici).parent.prepend(node)— lo aggiunge come primo figlio.target.before(node)/target.after(node)— inserisce un elemento sibling prima o dopotarget.parent.appendChild(node)— l'API classica; aggiunge un singolo nodo e lo restituisce.parent.insertBefore(node, reference)— inseriscenodeprima del figlioreference.
const list = document.createElement('ul');
const first = document.createElement('li');
first.textContent = 'First';
list.append(first);
const second = document.createElement('li');
second.textContent = 'Second';
list.append(second);
// Put a new item before the first one.
const top = document.createElement('li');
top.textContent = 'Top';
first.before(top);
console.log(list.children.length); // 3
console.log(list.firstElementChild.textContent); // TopPer inserire una stringa HTML in una posizione precisa senza rieseguire il parsing dell'intero genitore, usa insertAdjacentHTML():
const wrapper = document.createElement('div');
const box = document.createElement('div');
box.textContent = 'middle';
wrapper.append(box); // box must be in the tree to gain siblings
box.insertAdjacentHTML('beforebegin', '<span>before</span>');
box.insertAdjacentHTML('afterend', '<span>after</span>');
console.log(box.previousElementSibling.textContent); // before
console.log(box.nextElementSibling.textContent); // afterSostituzione e Rimozione di Elementi
oldNode.replaceWith(newNode)— sostituisceoldNodeconnewNodein posizione.element.remove()— scollega l'elemento dal DOM.parent.replaceChild(newNode, oldNode)eparent.removeChild(child)— gli equivalenti più datati.
const parent = document.createElement('div');
const a = document.createElement('p');
a.textContent = 'old';
parent.append(a);
const b = document.createElement('p');
b.textContent = 'new';
a.replaceWith(b);
console.log(parent.innerHTML); // <p>new</p>
b.remove();
console.log(parent.innerHTML); // (empty)I metodi moderni (append, prepend, before, after, replaceWith, remove) sono più leggibili rispetto ai metodi legacy appendChild/insertBefore/replaceChild/removeChild e accettano più nodi e stringhe contemporaneamente. Usali per primi; ricorri all'API legacy solo per supportare browser molto vecchi.
Best Practice per la Manipolazione del DOM
Minimizzare gli Accessi Diretti al DOM
Accedere al DOM può essere lento perché può costringere il browser a ricalcolare il layout e a ridisegnare gli elementi. Per minimizzare gli accessi diretti al DOM:
- Raggruppa gli aggiornamenti al DOM invece di eseguire più piccoli aggiornamenti separati.
- Usa variabili per memorizzare i riferimenti agli elementi acceduti frequentemente.
Ottimizzare la Gestione degli Eventi
Collega i gestori di eventi in modo efficiente:
- Usa la delegazione degli eventi per ridurre il numero di listener.
- Evita di collegare troppi listener direttamente agli elementi.
Pulire gli Elementi Non Necessari
Rimuovi gli elementi che non servono più per liberare memoria e migliorare le prestazioni:
- Usa i metodi
removeChildoremoveper eliminare gli elementi dal DOM.
Minimizzare Reflow e Repaint
Cosa Sono Reflow e Repaint?
- I Reflow si verificano quando cambia il layout di una parte della pagina, costringendo il browser a ricalcolare le posizioni e le dimensioni degli elementi.
- I Repaint avvengono quando cambia l'aspetto visivo degli elementi senza influenzare il layout (ad esempio, cambiamenti di colore).
Tecniche per Minimizzare Reflow e Repaint
Raggruppare le Modifiche
Raggruppa più modifiche insieme per evitare reflow e repaint ripetuti:
<!DOCTYPE html>
<html>
<head>
<title>Batching Changes</title>
</head>
<body>
<div id="content">Original Content</div>
<button id="update">Update Content</button>
<script>
document.getElementById('update').addEventListener('click', () => {
const content = document.getElementById('content');
content.style.display = 'none'; // Hide element to batch changes
content.innerHTML = 'Updated Content';
content.style.display = 'block'; // Show element after updates
});
</script>
</body>
</html>Questo esempio mostra come raggruppare le modifiche a un elemento DOM per minimizzare reflow e repaint. Nascondendo l'elemento prima di apportare più aggiornamenti e mostrandolo di nuovo dopo, è possibile evitare reflow e repaint intermedi.
Usare le Classi CSS per le Modifiche
Applica le modifiche CSS usando le classi anziché manipolare direttamente gli stili:
<!DOCTYPE html>
<html>
<head>
<title>Use CSS Classes</title>
<style>
.hidden { display: none; }
.highlight { color: red; font-weight: bold; }
</style>
</head>
<body>
<div id="content">Hello World</div>
<button id="toggle">Toggle Highlight</button>
<script>
document.getElementById('toggle').addEventListener('click', () => {
const content = document.getElementById('content');
content.classList.toggle('highlight');
});
</script>
</body>
</html>Questo esempio dimostra come usare le classi CSS per applicare più modifiche di stile contemporaneamente, il che è più efficiente rispetto alla modifica delle singole proprietà di stile. Alternare una classe che cambia più stili aiuta a ridurre il numero di reflow e repaint.
Uso dei Frammenti di Documento per le Prestazioni
Cos'è un Frammento di Documento?
Un Frammento di Documento è un contenitore leggero usato per raggruppare un insieme di nodi. Non fa parte dell'albero DOM principale, il che significa che le modifiche apportate ad esso non provocano reflow e repaint.
Quando si eseguono più manipolazioni del DOM, usa DocumentFragment per raggruppare le modifiche e aggiungerle al DOM in una singola operazione. Questo approccio minimizza reflow e repaint, migliorando significativamente le prestazioni.
Esempio di Utilizzo dei Frammenti di Documento
<!DOCTYPE html>
<html>
<head>
<title>Document Fragments</title>
</head>
<body>
<div id="list"></div>
<button id="populate">Populate List</button>
<script>
document.getElementById('populate').addEventListener('click', (event) => {
const fragment = document.createDocumentFragment();
for (let i = 1; i <= 25; i++) {
const item = document.createElement('div');
item.textContent = `Item ${i}`;
fragment.appendChild(item);
}
document.getElementById('list').appendChild(fragment);
event.target.disabled = true; // Disable the button
});
</script>
</body>
</html>Questo esempio crea 25 elementi div e li aggiunge a un Frammento di Documento. Solo dopo che tutti gli elementi sono stati aggiunti al frammento, il frammento viene inserito nel DOM in un'unica operazione. Questo approccio minimizza reflow e repaint aggiornando il DOM una sola volta.
Clonazione dei Nodi
Il Metodo cloneNode()
Il metodo cloneNode() viene utilizzato per creare una copia di un nodo. Può clonare il nodo stesso o il nodo insieme ai suoi figli.
Clonazione di un Nodo Senza Figli
<!DOCTYPE html>
<html>
<head>
<title>Cloning Nodes</title>
</head>
<body>
<div id="original">Original Node</div>
<button id="clone">Clone Node</button>
<script>
document.getElementById('clone').addEventListener('click', () => {
const original = document.getElementById('original');
const clone = original.cloneNode(false); // Clone without children
clone.id = 'clone';
clone.textContent = 'Cloned Node';
document.body.appendChild(clone);
});
</script>
</body>
</html>Questo esempio mostra come clonare un nodo senza i suoi figli usando il metodo cloneNode(false). Il nodo clonato copierà gli attributi e il contenuto testuale del nodo originale, ma non i suoi nodi figlio.
Clonazione di un Nodo Con Figli
<!DOCTYPE html>
<html>
<head>
<title>Cloning Nodes with Children</title>
</head>
<body>
<div id="original">
Original Node
<span>Child Node</span>
</div>
<button id="clone">Clone Node with Children</button>
<script>
document.getElementById('clone').addEventListener('click', () => {
const original = document.getElementById('original');
const clone = original.cloneNode(true); // Clone with children
clone.id = 'clone';
document.body.appendChild(clone);
});
</script>
</body>
</html>Questo esempio dimostra come clonare un nodo insieme ai suoi figli usando il metodo cloneNode(true). Il nodo clonato includerà il contenuto del nodo originale e tutti i suoi nodi discendenti.
Conclusione
La manipolazione efficiente del DOM è fondamentale per creare applicazioni web performanti. Inizia padroneggiando i metodi di base per creare, inserire, sostituire e rimuovere elementi, poi aggiungi le ottimizzazioni: raggruppa gli aggiornamenti, preferisci le classi CSS agli stili inline, usa DocumentFragment per inserimenti in blocco e clona i nodi quando hai bisogno di strutture ripetute. Insieme, queste tecniche mantengono le tue pagine reattive anche quando il DOM cresce.
Argomenti Correlati
- DOM Manipulation — una panoramica più ampia sulla lettura e la scrittura dell'albero del documento.
- Traversing the DOM — naviga tra genitori, figli e sibling.
- DOM Performance Optimization — approfondisci come mantenere veloce la manipolazione.
- Event Handling in the DOM — collega le interazioni in modo efficiente.