El Document Object Model (DOM) es la interfaz que permite a los programas y scripts acceder y manipular el contenido, la estructura y el estilo de los documentos HTML y XML. Es, en esencia, la representación de tu página web en forma de un árbol de objetos, donde cada nodo representa una parte del documento, como un elemento, un atributo o un nodo de texto. Manipular el DOM con JavaScript es una habilidad fundamental para cualquier desarrollador web, ya que te permite crear páginas interactivas y dinámicas que responden a las acciones del usuario.
Desde cambiar el texto de un párrafo hasta crear elementos complejos sobre la marcha, el DOM y JavaScript son el dúo dinámico que da vida a la interfaz de usuario. Entender cómo interactuar con este modelo es clave para construir experiencias web modernas y atractivas. En este post, te ofreceremos una recopilación de ejercicios prácticos de manipulación del DOM con JavaScript, diseñados para reforzar tus conocimientos y darte la confianza para crear tus propias soluciones interactivas.
A medida que avances en estos ejercicios, no solo comprenderás mejor los métodos y propiedades del DOM, sino que también desarrollarás una lógica de programación más sólida. ¡Prepárate para llevar tus habilidades de JavaScript al siguiente nivel! Si necesitas un repaso de los fundamentos de JavaScript antes de sumergirte en el DOM, te recomendamos visitar nuestra sección dedicada.
¿Por qué es tan importante dominar el DOM en JavaScript?
La importancia del DOM radica en su capacidad para transformar una página estática en una experiencia interactiva. Sin la manipulación del DOM, las páginas web serían meros documentos de texto sin vida. Con ella, podemos:
- Actualizar contenido dinámicamente: Cambiar textos, imágenes o cualquier otro elemento sin recargar la página. Piensa en un contador de «me gusta» en tiempo real o en la actualización de precios en una tienda online.
- Responder a eventos del usuario: Capturar clics, pulsaciones de teclas, movimientos del ratón y cualquier otra interacción, permitiendo que la página reaccione de forma inteligente.
- Crear elementos sobre la marcha: Añadir nuevos elementos HTML al documento basándose en la lógica de la aplicación, como la adición de ítems a una lista de tareas pendientes.
- Modificar estilos y clases CSS: Alterar la apariencia de los elementos para reflejar estados o interacciones, por ejemplo, resaltar un campo de formulario cuando el usuario hace clic en él.
Un estudio reciente de Stack Overflow Developer Survey 2023 destaca que JavaScript sigue siendo el lenguaje de programación más utilizado, y la manipulación del DOM es una de las tareas más comunes que realizan los desarrolladores web. Esto subraya la relevancia de dominar estos conceptos para el mercado laboral actual y futuro.
Ejercicio 1: Acceder al Elemento Padre de un Nodo y Cambiar su Estilo
A menudo, necesitas acceder al elemento que contiene a otro para modificarlo o aplicar estilos específicos. En este primer ejercicio, aprenderemos a navegar hacia arriba en el árbol DOM, desde un elemento hijo hasta su padre. Esto es útil para aplicar cambios de diseño o interactividad a un contenedor basándose en una acción dentro de uno de sus elementos internos.
Enunciado: Crea una página HTML con un div
que contenga un párrafo y un botón. Al hacer clic en el botón, el estilo del div
padre debe cambiar su color de fondo, color de texto y borde.
Objetivo del aprendizaje:
- Uso de
parentNode
para acceder al elemento padre. - Modificación de estilos inline con JavaScript.
- Implementación de un
eventListener
para un eventoclick
.
Código HTML:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Acceder al Padre</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
margin-top: 50px;
}
#contenedorPadre {
padding: 20px;
border: 1px solid #ccc;
text-align: center;
}
button {
margin-top: 10px;
padding: 8px 15px;
cursor: pointer;
}
</style>
</head>
<body>
<h1>Acceder al elemento padre de un nodo y cambiar su estilo.</h1>
<div id="contenedorPadre">
<p>Este es un contenedor</p>
<button id="cambiarPadre">Cambiar estilo del padre</button>
</div>
<script src="ejercicio1.js"></script>
</body>
</html>
Código JavaScript (ejercicio1.js):
/* Acceder al elemento padre de un nodo y cambiar su estilo. */
const boton = document.querySelector("#cambiarPadre");
boton.addEventListener("click", () => {
const padre = boton.parentElement;
padre.style.backgroundColor = "lightblue";
padre.style.color = "white";
padre.style.border = "2px solid dodgerblue";
});
Explicación:
- Obtenemos una referencia al botón utilizando
document.querySelector("#cambiarPadre")
. - Añadimos un
eventListener
al botón para que, cuando se haga clic, ejecute una función. - Dentro de la función, usamos
boton.parentElement
para obtener una referencia directa al elemento padre del botón (que en este caso es eldiv#contenedorPadre
). - Finalmente, modificamos las propiedades
backgroundColor
,color
yborder
delpadre
utilizando su propiedadstyle
. Esta es una forma directa de aplicar estilos CSS desde JavaScript.
Este ejercicio te proporciona una base sólida para entender cómo el DOM te permite navegar entre nodos y modificar sus propiedades, un concepto fundamental para construir interfaces dinámicas. Para profundizar más en la navegación del DOM, puedes consultar la documentación oficial del DOM en MDN Web Docs.
Ejercicio 2: Listar los Elementos Hijos de un Nodo
Aprender a acceder a los hijos de un elemento es tan importante como acceder a su padre. Este conocimiento te permite, por ejemplo, iterar sobre una lista de elementos generados dinámicamente o aplicar operaciones a todos los elementos dentro de un contenedor específico. En este ejercicio, crearemos una lista y mostraremos sus elementos hijos al hacer clic en un botón.
Enunciado: Crea una página HTML con una lista desordenada (ul
) que contenga varios elementos de lista (li
). Añade un botón que, al ser clicado, muestre cada uno de los elementos li
de la lista en un área de resultados.
Objetivo del aprendizaje:
- Uso de
children
para obtener una colección de elementos hijos. - Creación dinámica de elementos HTML (
document.createElement
). - Añadir elementos al DOM (
appendChild
). - Iteración sobre una colección de nodos.
Código HTML:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Listar Hijos</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
margin-top: 50px;
}
ul {
list-style: none;
padding: 0;
border: 1px solid #eee;
padding: 15px;
min-width: 200px;
}
li {
padding: 5px 0;
}
button {
margin-top: 10px;
padding: 8px 15px;
cursor: pointer;
}
#resultado {
margin-top: 20px;
border: 1px dashed #ccc;
padding: 15px;
min-width: 200px;
min-height: 50px;
}
</style>
</head>
<body>
<h1>Lista de hijos</h1>
<ul id="miLista">
<li>Elemento 1</li>
<li>Elemento 2</li>
<li>Elemento 3</li>
</ul>
<button id="listarHijos">Listar hijos</button>
<ul id="resultado"></ul>
<script src="ejercicio2.js"></script>
</body>
</html>
Código JavaScript (ejercicio2.js):
/* Lista de hijos */
const miLista = document.querySelector("#miLista");
const botonListar = document.querySelector("#listarHijos");
const resultadoUL = document.querySelector("#resultado");
botonListar.addEventListener("click", () => {
resultadoUL.innerHTML = ""; // Limpiar resultados anteriores
const hijos = miLista.children; // Obtener los elementos hijos
for (let i = 0; i < hijos.length; i++) {
const li = document.createElement("li");
li.textContent = hijos[i].textContent;
resultadoUL.appendChild(li);
}
});
Explicación:
- Obtenemos referencias a la lista (
miLista
), el botón (botonListar
) y la lista donde mostraremos los resultados (resultadoUL
). - Al hacer clic en
botonListar
, limpiamos el contenido deresultadoUL
para evitar duplicados en cada clic. - Usamos
miLista.children
para obtener unaHTMLCollection
de los elementos hijos directos demiLista
. Esta colección es «live», lo que significa que se actualiza automáticamente si los hijos demiLista
cambian. - Iteramos sobre esta colección con un bucle
for
. - En cada iteración, creamos un nuevo elemento
li
(document.createElement("li")
), le asignamos el texto del elemento hijo original y lo añadimos aresultadoUL
conappendChild()
.
Este ejercicio es fundamental para aprender a trabajar con colecciones de elementos y manipular listas dinámicamente, una tarea muy común en el desarrollo web. Para más información sobre children
y otras propiedades de nodos, puedes consultar recursos como la guía de nodos en W3C.
Ejercicio 3: Mover un Elemento entre Contenedores
La capacidad de mover elementos de un lugar a otro en el DOM es crucial para la interactividad avanzada. Esto puede ser útil para construir interfaces de arrastrar y soltar, o para reorganizar la estructura de una página basándose en las preferencias del usuario o en la lógica de la aplicación. En este ejercicio, implementaremos una lógica sencilla para mover un elemento entre dos div
contenedores.
Enunciado: Diseña una página con dos div
vacíos que actúen como contenedores y un div
adicional que sea el «elemento a mover». Crea un botón que, al ser pulsado, mueva el «elemento a mover» entre el primer y el segundo contenedor de forma alternada.
Objetivo del aprendizaje:
- Remover y añadir elementos al DOM.
- Controlar la posición de un elemento en función de su contenedor actual.
- Uso de
appendChild()
para reubicar un nodo existente.
Código HTML:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mover Elemento</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
margin-top: 50px;
}
.contenedor {
border: 2px dashed #666;
padding: 20px;
margin: 10px 0;
width: 300px;
min-height: 80px;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.9em;
color: #555;
}
#elementoAMover {
background-color: #f0f0f0;
border: 1px solid #aaa;
padding: 10px;
margin: 5px;
cursor: grab;
}
button {
margin-top: 20px;
padding: 10px 20px;
cursor: pointer;
}
</style>
</head>
<body>
<h1>Mover elemento entre contenedores</h1>
<div id="contenedor1" class="contenedor">
Contenedor 1
</div>
<div id="elementoAMover">
Soy el elemento a mover
</div>
<div id="contenedor2" class="contenedor">
Contenedor 2
</div>
<button id="moverBtn">Mover elemento</button>
<script src="ejercicio3.js"></script>
</body>
</html>
Código JavaScript (ejercicio3.js):
/* Mover elemento entre contenedores */
const elemento = document.querySelector("#elementoAMover");
const contenedor1 = document.querySelector("#contenedor1");
const contenedor2 = document.querySelector("#contenedor2");
const botonMover = document.querySelector("#moverBtn");
botonMover.addEventListener("click", () => {
// Si el elemento está en el contenedor 1, moverlo al contenedor 2
if (elemento.parentElement === contenedor1) {
contenedor2.appendChild(elemento);
} else { // Si no, significa que está fuera o en el contenedor 2, lo movemos al contenedor 1
contenedor1.appendChild(elemento);
}
});
Explicación:
- Obtenemos referencias al elemento a mover (
elemento
), los dos contenedores (contenedor1
,contenedor2
) y el botón (botonMover
). - En el
eventListener
del botón, comprobamos dónde se encuentra actualmenteelemento
utilizandoelemento.parentElement
. - Si su padre es
contenedor1
, significa que está en el primer contenedor o fue movido allí previamente. Lo movemos acontenedor2
usandocontenedor2.appendChild(elemento)
. Es importante destacar queappendChild()
automáticamente mueve el nodo si ya existe en el DOM, no lo duplica. - Si no está en
contenedor1
(es decir, está encontenedor2
o inicialmente fuera de ambos), lo movemos acontenedor1
.
Este ejercicio demuestra la flexibilidad del DOM para reestructurar dinámicamente tu página. Para escenarios más complejos de arrastrar y soltar, te puede interesar investigar la API de Drag and Drop de HTML5.
Ejercicio 4: Crear una Lista Reordenable (Subir y Bajar Elementos)
Crear listas reordenables es un patrón de interfaz de usuario común y un excelente ejercicio para practicar la manipulación del DOM. Implica cambiar el orden de los nodos dentro de su elemento padre, lo que requiere un buen entendimiento de las relaciones entre hermanos en el DOM.
Enunciado: Construye una lista desordenada (ul
) con varios elementos de lista (li
). Cada elemento li
debe contener dos botones: uno para «subir» el elemento en la lista y otro para «bajarlo». Los botones deben reordenar los elementos li
de forma interactiva.
Objetivo del aprendizaje:
- Navegación entre elementos hermanos (
previousElementSibling
,nextElementSibling
). - Inserción de nodos en una posición específica (
insertBefore
). - Manejo de eventos delegados para optimizar el rendimiento.
Código HTML:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lista Reordenable</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
margin-top: 50px;
}
ul {
list-style: none;
padding: 0;
width: 300px;
border: 1px solid #ccc;
padding: 10px;
}
li {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px;
margin-bottom: 5px;
border: 1px solid #eee;
background-color: #f9f9f9;
}
li:last-child {
margin-bottom: 0;
}
button {
background: none;
border: 1px solid #ccc;
padding: 3px 8px;
cursor: pointer;
margin-left: 5px;
}
button:hover {
background-color: #e0e0e0;
}
</style>
</head>
<body>
<h1>Lista reordenable</h1>
<ul id="miListaReordenable">
<li>Elemento 1
<div>
<button class="subir">▲</button>
<button class="bajar">▼</button>
</div>
</li>
<li>Elemento 2
<div>
<button class="subir">▲</button>
<button class="bajar">▼</button>
</div>
</li>
<li>Elemento 3
<div>
<button class="subir">▲</button>
<button class="bajar">▼</button>
</div>
</li>
</ul>
<script src="ejercicio4.js"></script>
</body>
</html>
Código JavaScript (ejercicio4.js):
/* Lista reordenable */
const listaReordenable = document.querySelector("#miListaReordenable");
listaReordenable.addEventListener("click", (e) => {
const li = e.target.parentElement.parentElement; // El <li> padre del botón
if (e.target.classList.contains("subir")) {
const prev = li.previousElementSibling;
if (prev) {
listaReordenable.insertBefore(li, prev);
}
} else if (e.target.classList.contains("bajar")) {
const next = li.nextElementSibling;
if (next) {
listaReordenable.insertBefore(next, li); // Insertar el 'next' antes del 'li' actual
}
}
});
Explicación:
- Obtenemos una referencia a la lista principal (
listaReordenable
). - Utilizamos un patrón de delegación de eventos: en lugar de añadir un
eventListener
a cada botón, lo añadimos solo a la lista principal. Cuando se produce un clic,e.target
nos dirá qué elemento específico fue clicado. Esto es más eficiente, especialmente en listas largas. - Determinamos el elemento
li
padre del botón clicado.e.target.parentElement
nos da eldiv
que contiene los botones, ye.target.parentElement.parentElement
nos da elli
. - Si el botón clicado tiene la clase «subir»:
- Obtenemos el elemento hermano anterior con
li.previousElementSibling
. - Si existe un hermano anterior (
prev
no esnull
), usamoslistaReordenable.insertBefore(li, prev)
. Esto mueve elli
actual justo antes de su hermano anterior.
- Obtenemos el elemento hermano anterior con
- Si el botón clicado tiene la clase «bajar»:
- Obtenemos el elemento hermano siguiente con
li.nextElementSibling
. - Si existe un hermano siguiente (
next
no esnull
), usamoslistaReordenable.insertBefore(next, li)
. Esto mueve el hermano siguiente justo antes delli
actual, logrando el efecto de «bajar» elli
actual.
- Obtenemos el elemento hermano siguiente con
Este ejercicio es un excelente ejemplo de cómo la combinación de navegación entre hermanos y la inserción de nodos puede crear interfaces de usuario interactivas complejas. La delegación de eventos es una técnica crucial para optimizar el rendimiento de tus aplicaciones web, especialmente cuando trabajas con muchos elementos interactivos. Para más detalles sobre la delegación de eventos, puedes consultar guías avanzadas sobre manejo de eventos en JavaScript.
Reflexiones Finales sobre la Manipulación del DOM
Estos ejercicios son solo la punta del iceberg de lo que puedes lograr con la manipulación del DOM en JavaScript. Desde la creación de componentes reutilizables hasta la implementación de animaciones complejas, el DOM es tu lienzo. La clave es practicar consistentemente y entender la estructura de árbol que subyace a cada página web.
Recuerda que, aunque modificar el DOM directamente es poderoso, a menudo en proyectos más grandes se utilizan frameworks y librerías (como React, Vue o Angular) que abstraen gran parte de esta manipulación, ofreciendo formas más declarativas y eficientes de construir interfaces de usuario. Sin embargo, entender los fundamentos del DOM es indispensable incluso cuando se utilizan estas herramientas, ya que te proporcionan una base sólida para depurar y optimizar tu código.
Si te interesa seguir profundizando en el mundo del desarrollo web, considera explorar otros temas como el manejo de formularios con JavaScript o cómo la API Fetch para llamadas asíncronas puede enriquecer aún más tus aplicaciones web.
Hemos llegado al final de nuestra exploración del Document Object Model y su manipulación con JavaScript. Con estos ejercicios básicos hemos conocido los conceptos fundamentales de su estructura de árbol hasta la ejecución de ejercicios prácticos, además he subido un vídeo a YouTube donde puedes ver el procedimiento de los ejercicios y una muestra real de ellos. Esta es la parte 6 de 6 el resto en el enlace puedes ver el resto de ejercicios.
Preguntas Frecuentes (FAQ)
¿Qué es el DOM en JavaScript?
El DOM (Document Object Model) es una interfaz de programación para documentos HTML y XML. Representa la estructura de una página web como un árbol de objetos, permitiendo que JavaScript acceda, modifique y actualice el contenido, la estructura y los estilos de los elementos de la página de forma dinámica.
¿Cuál es la diferencia entre parentElement
y parentNode
?
parentElement
devuelve el elemento padre del nodo especificado. Si el nodo no tiene un elemento padre (por ejemplo, es el document
o un documentFragment
), devuelve null
. parentNode
devuelve el padre de un nodo. La principal diferencia es que parentElement
siempre devolverá un elemento, mientras que parentNode
puede devolver cualquier tipo de nodo (como un nodo de texto o un comentario, aunque en la práctica para la mayoría de los elementos HTML, ambos se comportan de manera similar al devolver un elemento). Para la manipulación general del DOM con elementos HTML, parentElement
suele ser más específico y conveniente.
¿Por qué es mejor usar children
en lugar de childNodes
para obtener elementos hijos?
children
devuelve una HTMLCollection
que solo contiene nodos de tipo «elemento» (etiquetas HTML). En cambio, childNodes
devuelve una NodeList
que incluye todos los nodos hijos, incluidos nodos de texto (espacios en blanco, saltos de línea) y nodos de comentario. Para la mayoría de las tareas de manipulación de elementos HTML, children
es más práctico y limpio, ya que filtra automáticamente los nodos que no son elementos.
¿Cómo puedo mejorar el rendimiento al manipular el DOM con JavaScript?
Algunas prácticas recomendadas incluyen:
- Minimizar manipulaciones directas: Evita realizar muchas pequeñas operaciones de DOM consecutivas. Si vas a hacer múltiples cambios, es más eficiente construir el fragmento de DOM en memoria y luego insertarlo una sola vez.
- Delegación de eventos: En lugar de adjuntar event listeners a muchos elementos individuales, adjunta uno solo a un elemento padre y usa
e.target
para identificar el elemento específico que disparó el evento. - Reflow y Repaint: Comprende cómo las operaciones del DOM pueden causar reflows (recalculo del diseño) y repaints (redibujo de elementos). Intenta minimizar estas operaciones costosas, por ejemplo, modificando las propiedades de estilo en conjunto o utilizando clases CSS.
- Usar
DocumentFragment
: Para construir grandes secciones del DOM, usaDocumentFragment
para agrupar nodos y luego insertarlos en el DOM en una sola operación. - Utilizar frameworks/librerías: En aplicaciones complejas, frameworks como React o Vue gestionan la manipulación del DOM de manera optimizada, a menudo usando un «DOM virtual» para mejorar el rendimiento.