Técnicas de Manipulación del DOM en JavaScript
Aprende técnicas de manipulación del DOM en JavaScript: crear, insertar, reemplazar y eliminar elementos, y optimizar con fragmentos de documento y clonación de nodos para minimizar los reflujos.
La manipulación del DOM (Document Object Model) es un aspecto fundamental del desarrollo web que te permite crear páginas dinámicas e interactivas modificando la estructura, el contenido y los estilos del documento desde JavaScript. Esta guía comienza con las técnicas principales para crear, insertar, reemplazar y eliminar elementos, y luego avanza hacia las mejores prácticas y optimizaciones de rendimiento — agrupación de cambios, fragmentos de documento y clonación de nodos — que mantienen esos cambios rápidos.
Si aún no has seleccionado un elemento, comienza con selección de elementos del DOM. Para entender el árbol que estás modificando, consulta comprendiendo los nodos del DOM.
Técnicas Fundamentales de Manipulación
Cada cambio en el DOM pertenece a una de cuatro categorías: crear nodos, insertarlos, reemplazarlos o eliminarlos.
Crear Elementos
Usa document.createElement() para construir un elemento en memoria, luego establece su contenido y atributos antes de insertarlo en la página. Un nodo que creas no es visible hasta que lo adjuntas 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>Prefiere textContent sobre innerHTML cuando insertes texto plano — es más rápido y evita el riesgo de seguridad de inyectar HTML sin escapar.
Insertar Elementos
Una vez que un elemento existe, adjúntalo con uno de estos métodos:
parent.append(node)— agrega el nodo como último hijo (también acepta cadenas de texto simples).parent.prepend(node)— lo agrega como primer hijo.target.before(node)/target.after(node)— inserta un hermano antes o después detarget.parent.appendChild(node)— la API clásica; agrega un único nodo y lo devuelve.parent.insertBefore(node, reference)— insertanodeantes del hijoreference.
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); // TopPara insertar una cadena HTML en una posición precisa sin volver a analizar todo el padre, 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); // afterReemplazar y Eliminar Elementos
oldNode.replaceWith(newNode)— sustituyeoldNodepornewNodeen el mismo lugar.element.remove()— desconecta el elemento del DOM.parent.replaceChild(newNode, oldNode)yparent.removeChild(child)— los equivalentes más antiguos.
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)Los métodos modernos (append, prepend, before, after, replaceWith, remove) son más fáciles de leer que los heredados appendChild/insertBefore/replaceChild/removeChild y aceptan múltiples nodos y cadenas a la vez. Úsalos primero; recurre a la API heredada solo cuando debas dar soporte a navegadores muy antiguos.
Mejores Prácticas para la Manipulación del DOM
Minimizar el Acceso Directo al DOM
Acceder al DOM puede ser lento porque puede obligar al navegador a recalcular el diseño y volver a pintar los elementos. Para minimizar el acceso directo al DOM:
- Agrupa las actualizaciones del DOM en lugar de realizar múltiples actualizaciones pequeñas.
- Usa variables para almacenar referencias a elementos a los que se accede con frecuencia.
Optimizar el Manejo de Eventos
Adjunta manejadores de eventos de forma eficiente:
- Usa la delegación de eventos para reducir el número de escuchadores de eventos.
- Evita adjuntar demasiados escuchadores de eventos directamente a los elementos.
Limpiar Elementos No Utilizados
Elimina los elementos que ya no se necesitan para liberar memoria y mejorar el rendimiento:
- Usa los métodos
removeChildoremovepara eliminar elementos del DOM.
Minimizar Reflujos y Repintados
¿Qué Son los Reflujos y Repintados?
- Los reflujos ocurren cuando cambia el diseño de una parte de la página, lo que obliga al navegador a recalcular las posiciones y tamaños de los elementos.
- Los repintados ocurren cuando cambia la apariencia visual de los elementos sin afectar el diseño (por ejemplo, cambios de color).
Técnicas para Minimizar Reflujos y Repintados
Agrupar Cambios
Agrupa múltiples cambios para evitar reflujos y repintados repetidos:
<!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>Este ejemplo muestra cómo agrupar cambios en un elemento del DOM para minimizar los reflujos y repintados. Al ocultar el elemento antes de realizar múltiples actualizaciones y mostrarlo después, puedes evitar reflujos y repintados intermedios.
Usar Clases CSS para los Cambios
Aplica cambios de CSS usando clases en lugar de manipular los estilos directamente:
<!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>Este ejemplo demuestra cómo usar clases CSS para aplicar múltiples cambios de estilo a la vez, lo cual es más eficiente que modificar propiedades de estilo individuales. Alternar una clase que cambia múltiples estilos ayuda a reducir el número de reflujos y repintados.
Uso de Fragmentos de Documento para el Rendimiento
¿Qué Es un Fragmento de Documento?
Un Fragmento de Documento es un contenedor ligero que se utiliza para agrupar un conjunto de nodos. No forma parte del árbol principal del DOM, lo que significa que los cambios realizados en él no desencadenan reflujos ni repintados.
Cuando realices múltiples manipulaciones del DOM, usa DocumentFragment para agrupar los cambios y agregarlos al DOM en una sola operación. Este enfoque minimiza los reflujos y repintados, mejorando significativamente el rendimiento.
Ejemplo de Uso de Fragmentos de 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>Este ejemplo crea 25 elementos div y los añade a un Fragmento de Documento. Solo después de que todos los elementos se agregan al fragmento, este se incorpora al DOM en una sola operación. Este enfoque minimiza los reflujos y repintados al actualizar el DOM solo una vez.
Clonar Nodos
El Método cloneNode()
El método cloneNode() se utiliza para crear una copia de un nodo. Puede clonar el nodo en sí o el nodo junto con sus hijos.
Clonar un Nodo Sin Hijos
<!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>Este ejemplo demuestra cómo clonar un nodo sin sus hijos usando el método cloneNode(false). El nodo clonado copiará los atributos y el contenido de texto del nodo original, pero no sus nodos hijos.
Clonar un Nodo Con Hijos
<!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>Este ejemplo demuestra cómo clonar un nodo junto con sus hijos usando el método cloneNode(true). El nodo clonado incluirá el contenido del nodo original y todos sus nodos descendientes.
Conclusión
La manipulación eficiente del DOM es fundamental para crear aplicaciones web de alto rendimiento. Comienza dominando los métodos principales para crear, insertar, reemplazar y eliminar elementos, y luego incorpora las optimizaciones: agrupa tus actualizaciones, prefiere las clases CSS sobre los estilos en línea, usa DocumentFragment para inserciones masivas y clona nodos cuando necesites estructuras repetidas. Juntas, estas técnicas mantienen tus páginas reactivas incluso cuando el DOM crece.
Temas Relacionados
- Manipulación del DOM — un recorrido más amplio sobre la lectura y escritura del árbol del documento.
- Recorrido del DOM — navega entre padres, hijos y hermanos.
- Optimización del Rendimiento del DOM — profundiza en mantener la manipulación rápida.
- Manejo de Eventos en el DOM — conecta interacciones de forma eficiente.