SENA Centro de la Innovación, la Agroindustria y la Aviación Instructor: Alexander Patiño Londoño
Guía Completa

El DOM en
JavaScript

Document Object Model — del árbol al código interactivo

// 01

¿Qué es el DOM?

El DOM (Document Object Model) es la representación en memoria de un documento HTML o XML. Cuando el navegador carga una página web, convierte todo el HTML en un árbol de objetos JavaScript que podemos leer y modificar.

En palabras simples: el DOM es el puente entre tu código JavaScript y lo que el usuario ve en pantalla. Sin él, JavaScript sería ciego ante el contenido de la página.

💡 Dato clave
El DOM no es parte de JavaScript — es una API del navegador. Esto significa que está disponible en el navegador, pero no en Node.js (a menos que uses librerías como jsdom).

¿Cómo funciona?

El navegador sigue este proceso al cargar una página:

  HTML texto plano
        ↓
  Parsing (análisis) por el navegador
        ↓
  DOM Tree (árbol de nodos)
        ↓
  JavaScript puede leerlo y modificarlo
        ↓
  El navegador re-renderiza los cambios
// 02

La Estructura de Árbol

Todo en el DOM es un nodo. El documento es el nodo raíz, y cada elemento HTML, texto o comentario es un nodo hijo.

<!DOCTYPE html>
<html>
  <head>
    <title>Mi Página</title>
  </head>
  <body>
    <h1 id="titulo">Hola Mundo</h1>
    <p class="texto">Primer párrafo</p>
  </body>
</html>

Este HTML se convierte en el siguiente árbol de nodos:

document
└─ html
   ├─ head
   │  └─ title
   │     └─ "Mi Página"  ← nodo de texto
   └─ body
      ├─ h1  id="titulo"
      │  └─ "Hola Mundo"
      └─ p   class="texto"
         └─ "Primer párrafo"

Tipos de Nodos

Node.ELEMENT_NODE (1)
Elementos HTML como <div>, <p>, <span>. Son los más comunes.
Node.TEXT_NODE (3)
El texto dentro de un elemento. "Hola" en <p>Hola</p> es un nodo de texto.
Node.DOCUMENT_NODE (9)
El objeto document raíz. Punto de entrada a todo el DOM.
Node.COMMENT_NODE (8)
Comentarios HTML: <!-- así -->. También son nodos en el árbol.
// 03

Seleccionar Elementos

Antes de modificar un elemento, primero hay que encontrarlo. JavaScript ofrece varios métodos para esto, cada uno con sus ventajas:

Los 4 métodos esenciales

// ── Por ID (devuelve 1 elemento o null) ──
const titulo = document.getElementById('titulo');

// ── Por clase CSS (devuelve HTMLCollection) ──
const tarjetas = document.getElementsByClassName('tarjeta');

// ── Por selector CSS, el primero que coincida ──
const primer_boton = document.querySelector('button.activo');

// ── Por selector CSS, TODOS los que coincidan ──
const todos_botones = document.querySelectorAll('.btn');
⭐ Recomendación
Usa querySelector y querySelectorAll en la mayoría de casos. Aceptan cualquier selector CSS, lo que los hace muy poderosos y flexibles.

Navegación entre nodos

Una vez que tienes un nodo, puedes moverte por el árbol usando estas propiedades:

const lista = document.querySelector('ul');

lista.parentElement      // → elemento padre
lista.children           // → hijos elementos (HTMLCollection)
lista.firstElementChild  // → primer hijo elemento
lista.lastElementChild   // → último hijo elemento
lista.nextElementSibling // → hermano siguiente
lista.previousElementSibling // → hermano anterior
// 04

Manipular el DOM

Leer y modificar contenido

const elem = document.querySelector('#caja');

// Leer/escribir texto (seguro, escapa HTML)
elem.textContent;                   // → "texto actual"
elem.textContent = 'Nuevo texto';

// Leer/escribir HTML interno (¡cuidado con XSS!)
elem.innerHTML;                      // → "<b>html</b>"
elem.innerHTML = '<b>Negrita</b>';

// Valor de inputs y formularios
document.querySelector('input').value; // → "lo que escribió el usuario"

Atributos y clases CSS

const img = document.querySelector('img');

// ── Atributos ──
img.getAttribute('src');              // lee
img.setAttribute('src', 'nueva.jpg'); // escribe
img.removeAttribute('alt');          // elimina
img.hasAttribute('loading');         // verifica (true/false)

// ── Clases CSS (la forma moderna) ──
elem.classList.add('activo');         // agrega clase
elem.classList.remove('activo');      // quita clase
elem.classList.toggle('activo');      // alterna clase
elem.classList.contains('activo');   // → true / false

Estilos inline

const caja = document.querySelector('.caja');

caja.style.backgroundColor = '#7c3aed'; // camelCase en JS
caja.style.fontSize = '18px';
caja.style.display = 'none';           // ocultar elemento
caja.style.cssText = 'color: red; font-size: 20px'; // múltiples a la vez

Crear e insertar elementos

// 1. Crear el elemento
const nuevoItem = document.createElement('li');
nuevoItem.textContent = 'Nueva tarea';
nuevoItem.classList.add('item');

// 2. Insertarlo en el DOM
const lista = document.querySelector('#lista');

lista.appendChild(nuevoItem);            // al final
lista.prepend(nuevoItem);               // al inicio
lista.insertBefore(nuevoItem, lista.children[1]); // posición específica
lista.remove();                          // eliminar la lista entera
nuevoItem.remove();                      // eliminar el item
// 05

Eventos del DOM

Los eventos permiten que tu código reaccione a las acciones del usuario. Son el núcleo de la interactividad web.

const boton = document.querySelector('#btn');

// addEventListener es la forma correcta y moderna
boton.addEventListener('click', (event) => {
  console.log('¡Clic!', event);
  event.preventDefault(); // evita el comportamiento por defecto
  event.stopPropagation(); // evita que el evento suba al padre
});

// Remover el listener
function handler() { /* ... */ }
boton.addEventListener('click', handler);
boton.removeEventListener('click', handler);

Eventos más usados

click / dblclick
Clic simple o doble sobre cualquier elemento.
input / change
input dispara en cada tecla; change solo al perder el foco.
keydown / keyup
Tecla presionada/soltada. event.key dice cuál fue.
submit
Envío de formulario. Siempre usar con preventDefault().
mouseover / mouseout
Cursor entra/sale del elemento.
DOMContentLoaded
El DOM está listo. Se pone en document, no en un elemento.

Delegación de eventos

En vez de poner un listener en cada elemento hijo, ponlo en el padre y usa event.target:

// ❌ Ineficiente: un listener por cada botón
document.querySelectorAll('.btn').forEach(btn => {
  btn.addEventListener('click', handler);
});

// ✅ Eficiente: un solo listener en el padre
document.querySelector('#contenedor').addEventListener('click', (e) => {
  if (e.target.matches('.btn')) {
    handler(e);
  }
});
⚡ Por qué usar delegación
La delegación es crucial cuando agregas elementos dinámicamente al DOM. Los listeners en elementos que no existen aún no funcionan — pero el listener en el padre sí captura los nuevos hijos.
// 06 — Proyecto Práctico

App de Tareas

Una aplicación completa que usa todos los conceptos del DOM: createElement addEventListener classList.toggle querySelector remove()

📋 Gestor de Tareas DOM
0 tareas
Aún no hay tareas. ¡Agrega una arriba!
⬢ DOM Console — operaciones en tiempo real
00:00:00document.addEventListener('DOMContentLoaded') → DOM listo ✓

📄 El código que hace funcionar esta app

Cada vez que interactúas con la app, este código del DOM se ejecuta:

// ── 1. Seleccionar elementos del DOM ──
const input    = document.querySelector('#taskInput');
const addBtn   = document.querySelector('#addBtn');
const taskList = document.querySelector('#taskList');

// ── 2. Escuchar el evento "click" en el botón ──
addBtn.addEventListener('click', () => {
  const texto = input.value.trim();
  if (!texto) return;

  // ── 3. Crear nuevo elemento ──
  const item = document.createElement('div');
  item.classList.add('task-item');
  item.innerHTML = `
    <div class="task-checkbox"></div>
    <span class="task-text">${texto}</span>
    <button class="btn btn-danger">Eliminar</button>
  `;

  // ── 4. Insertar en el DOM ──
  taskList.appendChild(item);
  input.value = ''; // limpiar input
});

// ── 5. Delegación: escuchar clics en la lista ──
taskList.addEventListener('click', (e) => {
  // Completar tarea
  if (e.target.matches('.task-checkbox')) {
    e.target.classList.toggle('checked');
    e.target.nextElementSibling.classList.toggle('done');
  }
  // Eliminar tarea
  if (e.target.matches('.btn-danger')) {
    e.target.closest('.task-item').remove();
  }
});