Apuntes DAM
    Tema 5 de 7DWEC · 2º DAW

    Desarrollo Web en Entorno Cliente

    DOM, Eventos y Formularios

    El árbol DOM, seleccionar y modificar elementos sin XSS, crear nodos, eventos y su propagación, delegación, teclado, validación de formularios con la API del navegador y accesibilidad.

    75 min lecturaIntermedio

    1. El DOM: la página como un árbol de objetos

    Cuando el navegador lee el HTML no lo guarda como texto, sino que construye un árbol en memoria: el DOM (Document Object Model). Cada etiqueta se convierte en un nodo de tipo elemento, el texto que contiene en un nodo de texto, y todos cuelgan de un único nodo raíz, document. Lo que ves en pantalla es un reflejo de ese árbol: si JavaScript cambia un nodo, la página cambia al instante, sin recargar.

    El DOM es un árbol genealógico

    Padres e hijos
    Un <ul> es el padre de sus <li>, que son hermanos entre sí. Puedes moverte en cualquier dirección.
    Buscar a alguien
    querySelector encuentra un nodo con la misma sintaxis que usas en CSS.
    Cambiar la familia
    Puedes añadir hijos, mudarlos de rama o quitarlos, y la página se redibuja sola.

    Encontrar elementos

    Los dos métodos que usarás casi siempre son querySelector, que devuelve el primer elemento que encaja con un selector CSS (o null si no hay ninguno), y querySelectorAll, que devuelve todos en una lista estática que puedes recorrer con for…of o forEach. Una vez que tienes un elemento, puedes moverte a su alrededor con parentElement, children, nextElementSibling o closest(selector), que sube por los antepasados hasta encontrar uno que encaje: la usarás muchísimo con los eventos.

    Cómo dominar el DOM en JavaScript en 30 minutos 2025 — Carlos Azaustre - AprendiendoDEV

    2. Cambiar contenido, atributos y estilos

    Para cambiar el texto de un elemento usa textContent. Existe también innerHTML, que interpreta el texto como HTML, y aquí está una de las lecciones de seguridad más importantes del módulo: si metes con innerHTML algo que ha escrito un usuario, ese usuario puede colar un <img onerror="…"> y ejecutar su propio código en la página de otros. Es el ataque XSS (Cross-Site Scripting). La regla es sencilla: los datos del usuario, siempre con textContent o creando nodos.

    javascript
    1const tarjeta = document.querySelector(".tarjeta");
    2
    3tarjeta.querySelector("h3").textContent = nombreUsuario;   // seguro
    4tarjeta.classList.add("destacada");                         // add, remove, toggle, contains
    5tarjeta.dataset.id = "42";                                  // → atributo data-id="42"
    6tarjeta.setAttribute("aria-expanded", "true");
    7tarjeta.style.setProperty("--color", "#2563eb");            // mejor clases o variables CSS que estilos sueltos
    8
    9const li = document.createElement("li");
    10li.textContent = "Nuevo elemento";
    11document.querySelector("ul").append(li);                    // también prepend, before, after
    12li.remove();
    Quiero…UsaEvita
    Cambiar un textotextContentinnerHTML con datos del usuario
    Mostrar u ocultarhidden o una clase CSSCambiar style.display a mano en muchos sitios
    Guardar un dato en el elementodataset (data-*)Atributos inventados sin data-
    Insertar muchos elementosCrearlos y hacer un único append (o un DocumentFragment)Un append por elemento dentro de un bucle muy largo
    Repetir un bloque de HTML<template> y cloneNode(true)Construir HTML concatenando textos

    3. Eventos: reaccionar a lo que hace el usuario

    Una aplicación web se pasa la mayor parte del tiempo esperando: a que el usuario haga clic, escriba, envíe un formulario o mueva el ratón. Cada una de esas acciones genera un evento, y tu código se suscribe a los que le interesan con addEventListener(tipo, manejador). Cuando el evento ocurre, el navegador llama a tu función y le pasa un objeto con toda la información: qué elemento lo recibió, qué tecla se pulsó, dónde estaba el ratón…

    CategoríaEventosPropiedades útiles
    Ratón y punteroclick, dblclick, pointerdown, pointermove, contextmenuclientX, clientY, button
    Tecladokeydown, keyupkey ("Enter", "a", "ArrowUp"), ctrlKey, shiftKey
    Formulariosinput (cada cambio), change (al confirmar), submit, focus, blurtarget.value, target.checked
    Documento y ventanaDOMContentLoaded, load, resize, scrollwindow.innerWidth, scrollY

    Burbujeo y delegación

    Un evento no se queda en el elemento donde ocurrió: primero baja desde document hasta él (fase de captura) y después sube por todos sus antepasados (fase de burbuja). Por eso un clic en un <li> también lo puede escuchar el <ul> que lo contiene. Dentro del manejador, e.target es el elemento donde se hizo clic y e.currentTarget el que tiene el manejador.

    Esto permite una técnica fundamental, la delegación de eventos: en lugar de poner un manejador en cada elemento de una lista, pones uno solo en el contenedor y averiguas con e.target.closest() sobre qué elemento se actuó. Tiene dos ventajas enormes: usa menos memoria y funciona automáticamente con los elementos que añadas después.

    javascript
    1document.querySelector("#productos").addEventListener("click", (e) => {
    2  const boton = e.target.closest("button[data-accion]");
    3  if (!boton) return;                        // se hizo clic en otra parte
    4  const tarjeta = boton.closest(".producto");
    5  if (boton.dataset.accion === "borrar") tarjeta.remove();
    6});

    Dos métodos del objeto evento completan el cuadro. e.preventDefault() cancela la acción por defecto del navegador (seguir un enlace, enviar un formulario y recargar la página) y e.stopPropagation() impide que el evento siga subiendo. El primero lo usarás a menudo; el segundo, muy poco, porque romper la propagación suele causar más problemas de los que resuelve.

    Mira cómo sube un evento
    Consola
    (sin mensajes)

    4. Formularios y validación

    Los formularios son la principal forma de recoger datos del usuario, y validarlos bien es la diferencia entre una aplicación agradable y una frustrante. HTML ya valida mucho por sí solo con atributos como required, type="email", min, max, minlength o pattern. JavaScript entra en juego para las reglas que HTML no puede expresar (que dos contraseñas coincidan, que una fecha sea posterior a otra) y para mostrar los errores con tu propio diseño.

    1. Escucha el evento submit del formulario, no el clic del botón: así también funciona al pulsar Enter.
    2. Llama a e.preventDefault() si vas a gestionar el envío tú mismo (por ejemplo, con fetch).
    3. Lee los valores con campo.value (siempre texto) o todos a la vez con new FormData(form).
    4. Valida y muestra cada error junto a su campo, no en un único mensaje general.
    5. Marca los campos erróneos con aria-invalid="true" y enlaza el mensaje con aria-describedby para que los lectores de pantalla lo anuncien.

    La API de validación del navegador te da acceso a lo que ya comprueba HTML: campo.checkValidity() dice si es válido, campo.validity dice por qué no (valueMissing, typeMismatch, tooShort…) y campo.setCustomValidity("mensaje") te deja añadir tus propias reglas integradas con las del navegador.

    Recuerda la regla de oro

    La validación en el cliente mejora la experiencia, pero cualquiera puede saltársela desactivando JavaScript o enviando la petición a mano. El servidor siempre tiene que volver a validar los datos.

    5. Retos

    Estos retos son pequeñas piezas de aplicaciones reales. Las pruebas interactúan con la página como lo haría un usuario: escriben en los campos, pulsan botones, envían formularios y usan el teclado.

    🧩JS · DOMLista de tareasMedio

    Al enviar el formulario #nueva se añade a #lista un <li> con un <span> con el texto de #texto y un botón con la clase «borrar» (el campo se vacía y los textos en blanco se ignoran). Al hacer clic en el <span> de una tarea, el <li> alterna la clase «hecha»; el botón «borrar» elimina su tarea. #pendientes muestra siempre cuántas tareas no están hechas. Usa un único manejador de clics en la lista (delegación de eventos).

    index.htmlsolo lectura
    script.js
    Vista previa
    🧩JS · DOMFiltro de tabla en vivoMedio

    Mientras se escribe en #filtro, oculta (con la propiedad hidden) las filas del <tbody> cuyo texto no contenga lo escrito, sin distinguir mayúsculas. #resultados debe mostrar «N resultados» (o «1 resultado»). Con el filtro vacío se ven todas.

    index.htmlsolo lectura
    script.js
    Vista previa
    🧩JS · DOMPestañas accesiblesMedio

    Haz funcionar las pestañas: al pulsar un botón con role="tab", queda con aria-selected="true" (las demás con "false") y se muestra su panel (el indicado en aria-controls), ocultando los otros con hidden. Además, con las flechas derecha e izquierda sobre una pestaña se activa la siguiente o la anterior (de forma circular) y recibe el foco.

    index.htmlsolo lectura
    script.js
    Vista previa
    🧩JS · DOMValidar un formulario de registroDifícil

    Al enviar #registro, valida los campos y, por cada error, escribe el mensaje en su <span class="error"> (#e-email, #e-pass, #e-pass2, #e-edad) y marca el campo con aria-invalid="true"; los campos correctos quedan con el mensaje vacío y aria-invalid="false". Reglas: email con el formato texto@texto.texto → «Email no válido»; contraseña de al menos 8 caracteres → «Mínimo 8 caracteres»; repetir contraseña igual → «Las contraseñas no coinciden»; edad entera entre 14 y 120 → «Edad no válida». Si todo es correcto, #ok muestra «Registro completado». La página no debe recargarse nunca.

    index.htmlsolo lectura
    script.js
    Vista previa

    ¿Has terminado este tema?

    Crea una cuenta gratis para guardar qué temas has terminado, subir de nivel y ganar medallas.

    Guardar mi progreso