Manipulación del DOM
Aprende a interactuar con el HTML de tu página web usando JavaScript. El DOM te permite seleccionar, modificar, crear y eliminar elementos dinámicamente.
1. ¿Qué es el DOM?
El DOM (Document Object Model) es una representación en forma de árbol de tu página HTML. JavaScript puede acceder y modificar este árbol para cambiar dinámicamente el contenido, estilos y estructura de la página.
Ejemplo: Cuando tienes un <div> en tu HTML, JavaScript lo ve como un objeto que puedes manipular.
1<!-- HTML -->2<div id="mensaje">3 <h1>¡Hola!</h1>4 <p class="texto">Bienvenido a la web</p>5</div>6 7<script>8// JavaScript puede acceder y modificar estos elementos9const div = document.getElementById('mensaje');10const parrafo = document.querySelector('.texto');11 12// Cambiar el texto13parrafo.textContent = '¡Texto modificado desde JavaScript!';14</script>2. Seleccionar Elementos
Antes de modificar un elemento, necesitas seleccionarlo. JavaScript ofrece varios métodos para hacerlo:
querySelector y querySelectorAll
Los métodos más recomendados y modernos. Usan selectores CSS.
1// querySelector - Devuelve el PRIMER elemento que coincide2const titulo = document.querySelector('h1');3const primerBoton = document.querySelector('.btn');4const elemento = document.querySelector('#menu');5 6// querySelectorAll - Devuelve TODOS los elementos que coinciden7const todosLosParrafos = document.querySelectorAll('p');8const todosBotones = document.querySelectorAll('.btn');9 10// Iterar sobre los elementos11todosLosParrafos.forEach(parrafo => {12 console.log(parrafo.textContent);13});Otros métodos de selección
1// Por ID (más rápido, pero menos flexible)2const header = document.getElementById('header');3 4// Por clase (devuelve HTMLCollection, no Array)5const botones = document.getElementsByClassName('btn');6 7// Por etiqueta8const parrafos = document.getElementsByTagName('p');9 10// ⚠️ HTMLCollection NO es un array real11// Para usar forEach, conviértelo a array:12Array.from(botones).forEach(btn => {13 console.log(btn);14});Recomendación
Usa querySelector y querySelectorAll en el 99% de los casos. Son más flexibles y modernos.
3. ⚠️ ¿Qué devuelven los selectores?
Es muy importante entender que los diferentes métodos de selección devuelven tipos distintos de objetos. Esto afecta qué operaciones puedes realizar sobre ellos.
Comparación de tipos de retorno
1// querySelector - Devuelve UN ELEMENTO (Element) o null2const titulo = document.querySelector('h1');3console.log(titulo); // <h1>...</h1>4// ✅ Puedes acceder directamente a propiedades5titulo.textContent = 'Nuevo título';6 7// querySelectorAll - Devuelve un NODELIST (parecido a array)8const parrafos = document.querySelectorAll('p');9console.log(parrafos); // NodeList(3) [p, p, p]10// ✅ Tiene forEach11parrafos.forEach(p => console.log(p));12// ❌ NO tiene map, filter, reduce13// parrafos.map(p => p.textContent); // ERROR!14 15// getElementsByClassName - Devuelve un HTMLCOLLECTION16const botones = document.getElementsByClassName('btn');17console.log(botones); // HTMLCollection(2) [button.btn, button.btn]18// ❌ NO tiene forEach ni map19// botones.forEach(btn => console.log(btn)); // ERROR!20 21// getElementById - Devuelve UN ELEMENTO o null22const header = document.getElementById('header');23console.log(header); // <header id="header">...</header>Tabla comparativa
| Método | Devuelve | Tiene forEach | Métodos Array |
|---|---|---|---|
| querySelector() | Element | N/A (es un objeto) | N/A |
| querySelectorAll() | NodeList | ✅ Sí | ❌ No |
| getElementById() | Element | N/A (es un objeto) | N/A |
| getElementsByClassName() | HTMLCollection | ❌ No | ❌ No |
Convertir a Array para usar métodos completos
1// Problema: querySelectorAll devuelve NodeList sin map/filter2const parrafos = document.querySelectorAll('p');3// parrafos.map(p => p.textContent); // ❌ ERROR!4 5// Solución 1: Array.from()6const textos1 = Array.from(parrafos).map(p => p.textContent);7console.log(textos1); // ['Texto 1', 'Texto 2', 'Texto 3']8 9// Solución 2: Spread operator [...]10const textos2 = [...parrafos].map(p => p.textContent);11 12// Solución 3: Array.prototype.slice13const textos3 = Array.prototype.slice.call(parrafos).map(p => p.textContent);14 15// Lo mismo para HTMLCollection16const botones = document.getElementsByClassName('btn');17const arrayBotones = Array.from(botones);18arrayBotones.forEach(btn => btn.classList.add('activo'));19arrayBotones.filter(btn => btn.disabled === false);20arrayBotones.map(btn => btn.textContent);Consejo práctico
Si necesitas usar métodos de arrays (map, filter, reduce), convierte inmediatamente:
const elementos = Array.from(document.querySelectorAll('.item'));
4. Modificar Contenido
Una vez seleccionado un elemento, puedes modificar su contenido usando textContent o innerHTML.
1const titulo = document.querySelector('h1');2const contenedor = document.querySelector('#contenedor');3 4// textContent - Solo texto (más seguro)5titulo.textContent = '¡Nuevo título!';6 7// innerHTML - Puede incluir HTML (cuidado con XSS)8contenedor.innerHTML = '<p>Nuevo <strong>párrafo</strong></p>';9 10// Leer el contenido11console.log(titulo.textContent); // "¡Nuevo título!"12 13// Diferencia entre textContent e innerHTML14const div = document.querySelector('#ejemplo');15div.innerHTML = '<strong>Negrita</strong>';16console.log(div.textContent); // "Negrita" (sin etiquetas)17console.log(div.innerHTML); // "<strong>Negrita</strong>" (con etiquetas)¡Cuidado con innerHTML!
Si usas innerHTML con datos del usuario, puedes crear vulnerabilidades XSS. Usa textContent cuando solo necesites texto.
5. Modificar Atributos
1const imagen = document.querySelector('img');2const enlace = document.querySelector('a');3const input = document.querySelector('input');4 5// Cambiar atributos6imagen.src = 'nueva-imagen.jpg';7imagen.alt = 'Descripción de la imagen';8 9enlace.href = 'https://ejemplo.com';10enlace.target = '_blank';11 12input.value = 'Texto por defecto';13input.placeholder = 'Escribe algo...';14 15// getAttribute y setAttribute (forma genérica)16const dataId = enlace.getAttribute('data-id');17enlace.setAttribute('data-id', '123');18 19// Verificar si tiene un atributo20if (enlace.hasAttribute('target')) {21 console.log('El enlace se abre en nueva pestaña');22}23 24// Eliminar un atributo25enlace.removeAttribute('target');6. Trabajar con Clases CSS
El objeto classList es la forma moderna y recomendada de trabajar con clases CSS.
1const boton = document.querySelector('.btn');2 3// Añadir una clase4boton.classList.add('activo');5boton.classList.add('btn-grande', 'destacado'); // Múltiples clases6 7// Eliminar una clase8boton.classList.remove('activo');9 10// Alternar una clase (toggle)11boton.classList.toggle('activo'); // Si existe, la elimina. Si no, la añade12 13// Verificar si tiene una clase14if (boton.classList.contains('activo')) {15 console.log('El botón está activo');16}17 18// Reemplazar una clase19boton.classList.replace('btn-grande', 'btn-pequeño');20 21// Ver todas las clases22console.log(boton.classList); // DOMTokenList ["btn", "activo"]Modificar estilos directamente
1const caja = document.querySelector('.caja');2 3// Modificar estilos inline4caja.style.backgroundColor = '#3b82f6';5caja.style.color = 'white';6caja.style.padding = '20px';7caja.style.borderRadius = '10px';8 9// Propiedades CSS con guiones → camelCase10caja.style.fontSize = '18px'; // font-size11caja.style.marginTop = '10px'; // margin-top12 13// ⚠️ Esto crea estilos inline (no recomendado)14// Mejor usar classList para añadir/quitar clases CSSBuena práctica
Usa classList para cambiar estilos. Define las clases CSS en tu archivo CSS y añádelas/quítalas con JavaScript. Es más mantenible.
7. Crear y Añadir Elementos
1<!-- HTML inicial -->2<div id="contenedor">3 <p>Primer párrafo existente</p>4</div>5 6<style>7 #contenedor {8 border: 2px solid #3b82f6;9 padding: 20px;10 margin: 20px 0;11 }12 13 .destacado {14 background-color: #fbbf24;15 color: #1f2937;16 padding: 10px;17 border-radius: 5px;18 font-weight: bold;19 }20</style>21 22<script>23// 1. Crear un elemento24const nuevoParrafo = document.createElement('p');25 26// 2. Configurar el elemento27nuevoParrafo.textContent = 'Este es un nuevo párrafo';28nuevoParrafo.classList.add('destacado');29 30// 3. Añadir al DOM31const contenedor = document.querySelector('#contenedor');32contenedor.append(nuevoParrafo); // Al final del contenedor33 34// Resultado:35// <div id="contenedor">36// <p>Primer párrafo existente</p>37// <p class="destacado">Este es un nuevo párrafo</p>38// </div>39</script>Diferentes métodos para añadir elementos
1<!-- HTML inicial -->2<div id="contenedor">3 <p>Párrafo del medio</p>4</div>5 6<script>7const contenedor = document.querySelector('#contenedor');8 9// 1. append() - Añade AL FINAL del contenedor10const p1 = document.createElement('p');11p1.textContent = 'Al final';12contenedor.append(p1);13 14// 2. prepend() - Añade AL PRINCIPIO del contenedor15const p2 = document.createElement('p');16p2.textContent = 'Al principio';17contenedor.prepend(p2);18 19// 3. before() - Añade ANTES del contenedor (como hermano)20const p3 = document.createElement('p');21p3.textContent = 'Antes del contenedor';22contenedor.before(p3);23 24// 4. after() - Añade DESPUÉS del contenedor (como hermano)25const p4 = document.createElement('p');26p4.textContent = 'Después del contenedor';27contenedor.after(p4);28 29// Resultado final:30// <p>Antes del contenedor</p>31// <div id="contenedor">32// <p>Al principio</p>33// <p>Párrafo del medio</p>34// <p>Al final</p>35// </div>36// <p>Después del contenedor</p>37</script>Ejemplo completo: Crear elementos desde JavaScript
En este ejemplo, JavaScript crea TODO desde cero: el contenedor, las tarjetas, y todo su contenido. El HTML está prácticamente vacío.
📄 index.html
1<!DOCTYPE html>2<html lang="es">3<head>4 <meta charset="UTF-8">5 <title>Crear Tarjetas</title>6 <style>7 body {8 font-family: Arial, sans-serif;9 padding: 20px;10 background-color: #f5f5f5;11 }12 13 .tarjeta {14 background-color: white;15 margin: 15px 0;16 }17 </style>18</head>19<body>20 <!-- Body completamente vacío -->21 <!-- JavaScript creará TODO -->22 <script src="app.js"></script>23</body>24</html>📄 app.js
1// 1. Crear el contenedor principal2const contenedor = document.createElement('div');3contenedor.id = 'contenedor';4 5// Aplicar estilos con .style6contenedor.style.maxWidth = '800px';7contenedor.style.margin = '0 auto';8 9// 2. Añadir el contenedor al body10document.body.append(contenedor);11 12// 3. Función para crear tarjetas13function crearTarjeta(titulo, descripcion) {14 // Crear elementos15 const tarjeta = document.createElement('div');16 const h3 = document.createElement('h3');17 const p = document.createElement('p');18 const boton = document.createElement('button');19 20 // Configurar contenido21 h3.textContent = titulo;22 p.textContent = descripcion;23 boton.textContent = 'Ver más';24 25 // Añadir clase CSS (definida en HTML)26 tarjeta.classList.add('tarjeta');27 28 // Añadir estilos con .style (inline)29 tarjeta.style.border = '1px solid #ddd';30 tarjeta.style.borderRadius = '8px';31 tarjeta.style.padding = '20px';32 tarjeta.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)';33 34 h3.style.margin = '0 0 10px 0';35 h3.style.color = '#333';36 37 p.style.color = '#666';38 p.style.marginBottom = '15px';39 40 boton.style.padding = '8px 16px';41 boton.style.border = 'none';42 boton.style.borderRadius = '4px';43 boton.style.backgroundColor = '#3b82f6';44 boton.style.color = 'white';45 boton.style.cursor = 'pointer';46 47 // Ensamblar la tarjeta48 tarjeta.append(h3, p, boton);49 50 return tarjeta;51}52 53// 4. Crear y añadir varias tarjetas54contenedor.append(55 crearTarjeta(56 'JavaScript',57 'Lenguaje de programación para web'58 )59);60 61contenedor.append(62 crearTarjeta(63 'Manipulación del DOM',64 'Crear y modificar elementos HTML'65 )66);67 68contenedor.append(69 crearTarjeta(70 'Eventos',71 'Interactuar con acciones del usuario'72 )73);La POTENCIA del dom
Fíjate que el HTML está prácticamente vacío. JavaScript crea:
- El
<div id="contenedor">principal - Cada
<div class="tarjeta"> - Los elementos internos:
<h3>,<p>,<button> - Añade clases CSS automáticamente
Esto es lo que hacen los frameworks modernos (React, Vue, ,Nextjs, Svelte) pero de forma más avanzada.
8. Eliminar Elementos
1const elemento = document.querySelector('.eliminar');2 3// Forma moderna (recomendada)4elemento.remove();5 6// Forma antigua (todavía funcional)7elemento.parentNode.removeChild(elemento);8 9// Eliminar todos los hijos de un contenedor10const contenedor = document.querySelector('#contenedor');11contenedor.innerHTML = ''; // Vaciar completamente12 13// O usando un bucle14while (contenedor.firstChild) {15 contenedor.removeChild(contenedor.firstChild);16}9. Navegar por el DOM
1const elemento = document.querySelector('.item');2 3// Padres4elemento.parentNode; // Nodo padre5elemento.parentElement; // Elemento padre6elemento.closest('.contenedor'); // Ancestro más cercano que coincide7 8// Hijos9elemento.children; // HTMLCollection de hijos10elemento.firstElementChild; // Primer hijo11elemento.lastElementChild; // Último hijo12elemento.childNodes; // Todos los nodos (incluye texto)13 14// Hermanos15elemento.nextElementSibling; // Siguiente hermano16elemento.previousElementSibling; // Hermano anterior10. Ejercicios Prácticos
Ejercicio 1: Cambiar Texto y Estilos
Crea una página HTML con un título y un botón. Al hacer clic en el botón:
- Cambia el texto del título
- Añade la clase
destacadoal título - Cambia el color de fondo del botón
Ver solución
1<!DOCTYPE html>2<html>3<head>4 <style>5 .destacado {6 color: #3b82f6;7 font-size: 2em;8 }9 </style>10</head>11<body>12 <h1 id="titulo">Título Original</h1>13 <button id="btn">Cambiar</button>14 15 <script>16 const titulo = document.querySelector('#titulo');17 const boton = document.querySelector('#btn');18 19 boton.addEventListener('click', () => {20 // Cambiar texto21 titulo.textContent = '¡Título Cambiado!';22 23 // Añadir clase24 titulo.classList.add('destacado');25 26 // Cambiar estilo del botón27 boton.style.backgroundColor = '#10b981';28 boton.style.color = 'white';29 });30 </script>31</body>32</html>Ejercicio 2: Lista de Tareas
Crea una lista de tareas simple:
- Un input para escribir la tarea
- Un botón "Añadir" que cree un nuevo elemento <li> con el texto del input
- Cada tarea debe añadirse a una lista <ul>
Ver solución
1<!DOCTYPE html>2<html>3<body>4 <input type="text" id="input" placeholder="Nueva tarea...">5 <button id="agregar">Añadir</button>6 <ul id="lista"></ul>7 8 <script>9 const input = document.querySelector('#input');10 const boton = document.querySelector('#agregar');11 const lista = document.querySelector('#lista');12 13 boton.addEventListener('click', () => {14 const texto = input.value.trim();15 16 if (texto === '') {17 alert('Escribe una tarea');18 return;19 }20 21 // Crear nuevo elemento li22 const tarea = document.createElement('li');23 tarea.textContent = texto;24 25 // Añadir a la lista26 lista.append(tarea);27 28 // Limpiar input29 input.value = '';30 input.focus();31 });32 33 // Bonus: Añadir con Enter34 input.addEventListener('keypress', (e) => {35 if (e.key === 'Enter') {36 boton.click();37 }38 });39 </script>40</body>41</html>Ejercicio 3: Galería de Imágenes
Crea una galería que:
- Muestre miniaturas de imágenes
- Al hacer clic en una miniatura, cambie la imagen principal
- Use
classList.add()para resaltar la miniatura activa
Ver solución
1<!DOCTYPE html>2<html>3<head>4 <style>5 #principal { width: 400px; display: block; }6 .miniatura { width: 80px; cursor: pointer; margin: 5px; }7 .activa { border: 3px solid #3b82f6; }8 </style>9</head>10<body>11 <img id="principal" src="img1.jpg" alt="Imagen principal">12 <div id="miniaturas">13 <img class="miniatura activa" src="img1.jpg" data-img="img1.jpg">14 <img class="miniatura" src="img2.jpg" data-img="img2.jpg">15 <img class="miniatura" src="img3.jpg" data-img="img3.jpg">16 </div>17 18 <script>19 const principal = document.querySelector('#principal');20 const miniaturas = document.querySelectorAll('.miniatura');21 22 miniaturas.forEach(mini => {23 mini.addEventListener('click', () => {24 // Cambiar imagen principal25 const nuevaSrc = mini.getAttribute('data-img');26 principal.src = nuevaSrc;27 28 // Quitar clase activa de todas29 miniaturas.forEach(m => m.classList.remove('activa'));30 31 // Añadir clase activa a la clickeada32 mini.classList.add('activa');33 });34 });35 </script>36</body>37</html>Ejercicio 4: Contador con Botones
Crea un contador con tres botones:
- Botón "+" que incremente el contador
- Botón "-" que decremente el contador
- Botón "Reset" que lo vuelva a 0
- El número debe mostrarse en un elemento con id
contador
Ver solución
1<!DOCTYPE html>2<html>3<body>4 <h1 id="contador">0</h1>5 <button id="incrementar">+</button>6 <button id="decrementar">-</button>7 <button id="reset">Reset</button>8 9 <script>10 const contadorEl = document.querySelector('#contador');11 const btnInc = document.querySelector('#incrementar');12 const btnDec = document.querySelector('#decrementar');13 const btnReset = document.querySelector('#reset');14 15 let contador = 0;16 17 function actualizarContador() {18 contadorEl.textContent = contador;19 20 // Bonus: Cambiar color según el valor21 if (contador > 0) {22 contadorEl.style.color = '#10b981';23 } else if (contador < 0) {24 contadorEl.style.color = '#ef4444';25 } else {26 contadorEl.style.color = '#64748b';27 }28 }29 30 btnInc.addEventListener('click', () => {31 contador++;32 actualizarContador();33 });34 35 btnDec.addEventListener('click', () => {36 contador--;37 actualizarContador();38 });39 40 btnReset.addEventListener('click', () => {41 contador = 0;42 actualizarContador();43 });44 </script>45</body>46</html>