Recopilación de ejercicios DOM JavaScript 6

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 evento click.

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:

  1. Obtenemos una referencia al botón utilizando document.querySelector("#cambiarPadre").
  2. Añadimos un eventListener al botón para que, cuando se haga clic, ejecute una función.
  3. Dentro de la función, usamos boton.parentElement para obtener una referencia directa al elemento padre del botón (que en este caso es el div#contenedorPadre).
  4. Finalmente, modificamos las propiedades backgroundColor, color y border del padre utilizando su propiedad style. 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:

  1. Obtenemos referencias a la lista (miLista), el botón (botonListar) y la lista donde mostraremos los resultados (resultadoUL).
  2. Al hacer clic en botonListar, limpiamos el contenido de resultadoUL para evitar duplicados en cada clic.
  3. Usamos miLista.children para obtener una HTMLCollection de los elementos hijos directos de miLista. Esta colección es «live», lo que significa que se actualiza automáticamente si los hijos de miLista cambian.
  4. Iteramos sobre esta colección con un bucle for.
  5. En cada iteración, creamos un nuevo elemento li (document.createElement("li")), le asignamos el texto del elemento hijo original y lo añadimos a resultadoUL con appendChild().

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:

  1. Obtenemos referencias al elemento a mover (elemento), los dos contenedores (contenedor1, contenedor2) y el botón (botonMover).
  2. En el eventListener del botón, comprobamos dónde se encuentra actualmente elemento utilizando elemento.parentElement.
  3. Si su padre es contenedor1, significa que está en el primer contenedor o fue movido allí previamente. Lo movemos a contenedor2 usando contenedor2.appendChild(elemento). Es importante destacar que appendChild() automáticamente mueve el nodo si ya existe en el DOM, no lo duplica.
  4. Si no está en contenedor1 (es decir, está en contenedor2 o inicialmente fuera de ambos), lo movemos a contenedor1.

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:

  1. Obtenemos una referencia a la lista principal (listaReordenable).
  2. 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.
  3. Determinamos el elemento li padre del botón clicado. e.target.parentElement nos da el div que contiene los botones, y e.target.parentElement.parentElement nos da el li.
  4. Si el botón clicado tiene la clase «subir»:
    • Obtenemos el elemento hermano anterior con li.previousElementSibling.
    • Si existe un hermano anterior (prev no es null), usamos listaReordenable.insertBefore(li, prev). Esto mueve el li actual justo antes de su hermano anterior.
  5. Si el botón clicado tiene la clase «bajar»:
    • Obtenemos el elemento hermano siguiente con li.nextElementSibling.
    • Si existe un hermano siguiente (next no es null), usamos listaReordenable.insertBefore(next, li). Esto mueve el hermano siguiente justo antes del li actual, logrando el efecto de «bajar» el li actual.

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:

  1. 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.
  2. 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.
  3. 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.
  4. Usar DocumentFragment: Para construir grandes secciones del DOM, usa DocumentFragment para agrupar nodos y luego insertarlos en el DOM en una sola operación.
  5. 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.
Scroll al inicio