Creación y eliminación de elementos
Introducción
Hasta ahora hemos aprendido a seleccionar elementos del DOM y modificar su contenido y atributos. El siguiente paso es dominar la creación y eliminación de elementos, lo que nos permitirá alterar dinámicamente la estructura de nuestra página web. Esta capacidad es fundamental para crear interfaces interactivas que respondan a las acciones del usuario o a datos recibidos del servidor. En este artículo, exploraremos cómo crear nuevos elementos HTML, insertarlos en el documento, clonar elementos existentes y eliminar aquellos que ya no necesitamos.
Creación de elementos con createElement
El método createElement
nos permite crear nuevos elementos HTML desde JavaScript:
// Crear un nuevo elemento párrafo
const nuevoPárrafo = document.createElement("p");
// Crear un nuevo elemento imagen
const nuevaImagen = document.createElement("img");
// Crear un nuevo elemento botón
const nuevoBoton = document.createElement("button");
El método acepta como parámetro el nombre de la etiqueta HTML que queremos crear. Sin embargo, estos elementos recién creados aún no forman parte del documento. Son como elementos "flotantes" que necesitan ser insertados para que el usuario los vea.
Configuración del nuevo elemento
Después de crear un elemento, necesitamos configurarlo antes de insertarlo en el DOM:
// Crear un nuevo elemento párrafo
const parrafo = document.createElement("p");
// Añadir contenido de texto
parrafo.textContent = "Este es un nuevo párrafo creado con JavaScript";
// Añadir atributos
parrafo.className = "destacado";
parrafo.id = "parrafo-nuevo";
parrafo.setAttribute("data-info", "creado-dinamicamente");
// Añadir estilos inline (si es necesario)
parrafo.style.color = "blue";
parrafo.style.marginTop = "20px";
También podemos crear y configurar elementos más complejos, como imágenes o enlaces:
// Crear una imagen
const imagen = document.createElement("img");
imagen.src = "imagen.jpg";
imagen.alt = "Descripción de la imagen";
imagen.width = 300;
// Crear un enlace
const enlace = document.createElement("a");
enlace.href = "https://ejemplo.com";
enlace.textContent = "Visitar sitio web";
enlace.target = "_blank";
Inserción de elementos en el DOM
Una vez que hemos creado y configurado un elemento, tenemos varias formas de insertarlo en el DOM.
Métodos append y prepend
Los métodos modernos append
y prepend
nos permiten añadir elementos al principio o al final de un elemento contenedor:
const contenedor = document.getElementById("contenedor");
const nuevoElemento = document.createElement("div");
nuevoElemento.textContent = "Nuevo contenido";
// Añadir al final del contenedor
contenedor.append(nuevoElemento);
// Añadir al principio del contenedor
// contenedor.prepend(nuevoElemento);
// Podemos añadir múltiples elementos a la vez
// contenedor.append(elemento1, elemento2, "También podemos añadir texto directamente");
Métodos appendChild y insertBefore
Estos métodos más tradicionales también permiten insertar elementos:
const lista = document.getElementById("mi-lista");
const nuevoItem = document.createElement("li");
nuevoItem.textContent = "Nuevo elemento de lista";
// Añadir al final con appendChild
lista.appendChild(nuevoItem);
// Insertar antes de un elemento específico
const referenciaItem = document.getElementById("item-referencia");
const otroItem = document.createElement("li");
otroItem.textContent = "Elemento insertado en medio";
lista.insertBefore(otroItem, referenciaItem);
Diferencias clave:
appendChild
solo acepta nodos (no texto directo) y solo uno a la vezappend
puede recibir múltiples nodos y también cadenas de textoinsertBefore
requiere un nodo de referencia
Métodos after y before
Los métodos after
y before
permiten insertar elementos adyacentes a un elemento existente:
const elementoReferencia = document.getElementById("elemento-referencia");
const nuevoElemento = document.createElement("p");
nuevoElemento.textContent = "Elemento adyacente";
// Insertar después del elemento de referencia
elementoReferencia.after(nuevoElemento);
// Insertar antes del elemento de referencia
// elementoReferencia.before(nuevoElemento);
Método insertAdjacentElement
Este método ofrece un control más preciso sobre la ubicación de inserción:
const referencia = document.getElementById("referencia");
const nuevoElemento = document.createElement("div");
nuevoElemento.textContent = "Elemento posicionado con precisión";
// Posiciones disponibles:
referencia.insertAdjacentElement("beforebegin", nuevoElemento); // Antes del elemento
// referencia.insertAdjacentElement("afterbegin", nuevoElemento); // Dentro, al principio
// referencia.insertAdjacentElement("beforeend", nuevoElemento); // Dentro, al final
// referencia.insertAdjacentElement("afterend", nuevoElemento); // Después del elemento
Clonar elementos existentes
A veces es más conveniente clonar un elemento existente que crear uno nuevo desde cero:
const elementoOriginal = document.getElementById("template-item");
const clon = elementoOriginal.cloneNode(false);
// cloneNode(false) clona solo el elemento
// cloneNode(true) clona el elemento y todos sus descendientes
// Modificar el clon
clon.id = "nuevo-id";
clon.textContent = "Contenido del clon";
// Insertar el clon en el documento
document.getElementById("contenedor").appendChild(clon);
La clonación es particularmente útil cuando necesitamos crear múltiples elementos con estructura similar, como filas de una tabla o elementos de una lista.
Eliminar elementos con remove
Para eliminar elementos del DOM, el método moderno más sencillo es remove()
:
const elementoAEliminar = document.getElementById("elemento-obsoleto");
// Eliminar el elemento directamente
elementoAEliminar.remove();
// También podemos verificar primero si existe
if (elementoAEliminar) {
elementoAEliminar.remove();
}
Reemplazar elementos
Podemos reemplazar un elemento existente por uno nuevo:
const elementoViejo = document.getElementById("elemento-antiguo");
const elementoNuevo = document.createElement("div");
elementoNuevo.textContent = "Soy el reemplazo";
elementoNuevo.className = "destacado";
// Método moderno
elementoViejo.replaceWith(elementoNuevo);
// Método tradicional (desde el padre)
// const padre = elementoViejo.parentNode;
// padre.replaceChild(elementoNuevo, elementoViejo);
Fragmentos de documento
Los fragmentos de documento son contenedores temporales que nos permiten preparar un conjunto de elementos antes de insertarlos en el DOM, mejorando significativamente el rendimiento:
// Crear un fragmento
const fragmento = document.createDocumentFragment();
// Añadir elementos al fragmento
for (let i = 1; i <= 100; i++) {
const item = document.createElement("li");
item.textContent = `Elemento ${i}`;
fragmento.appendChild(item);
}
// Insertar todo el fragmento de una sola vez
const lista = document.getElementById("mi-lista");
lista.appendChild(fragmento);
Usar fragmentos tiene ventajas importantes:
- Evita múltiples reflow y repaint (mejora el rendimiento)
- No crea un nodo contenedor adicional
- Es la forma más eficiente de insertar múltiples elementos
Rendimiento en manipulaciones masivas
La manipulación del DOM puede ser costosa en términos de rendimiento, especialmente cuando añadimos o eliminamos muchos elementos. Aquí hay algunas estrategias para optimizar estas operaciones:
Problema: Añadir muchos elementos individualmente
// INEFICIENTE: Causa múltiples reflow
const lista = document.getElementById("mi-lista");
for (let i = 0; i < 1000; i++) {
const item = document.createElement("li");
item.textContent = `Item ${i}`;
lista.appendChild(item); // Cada append causa un reflow
}
Solución 1: Usar un fragmento de documento
// EFICIENTE: Un solo reflow al final
const lista = document.getElementById("mi-lista");
const fragmento = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const item = document.createElement("li");
item.textContent = `Item ${i}`;
fragmento.appendChild(item);
}
lista.appendChild(fragmento); // Un solo reflow
Solución 2: Construcción con innerHTML (cuidado con la seguridad)
// EFICIENTE pero potencialmente inseguro con datos no controlados
const lista = document.getElementById("mi-lista");
let html = "";
for (let i = 0; i < 1000; i++) {
html += `<li>Item ${i}</li>`;
}
lista.innerHTML = html; // Un solo reflow
Solución 3: Desconectar y reconectar el nodo
// EFICIENTE: Trabajar fuera del DOM visible
const lista = document.getElementById("mi-lista");
const padre = lista.parentNode;
const siguiente = lista.nextSibling;
// Desconectar del DOM
padre.removeChild(lista);
// Realizar múltiples operaciones
for (let i = 0; i < 1000; i++) {
const item = document.createElement("li");
item.textContent = `Item ${i}`;
lista.appendChild(item);
}
// Reconectar al DOM
padre.insertBefore(lista, siguiente);
Ejemplos prácticos
Ejemplo 1: Lista de tareas dinámica
// HTML básico:
// <input id="nueva-tarea" type="text" placeholder="Nueva tarea...">
// <button id="agregar">Agregar</button>
// <ul id="lista-tareas"></ul>
document.getElementById("agregar").addEventListener("click", function() {
const input = document.getElementById("nueva-tarea");
const textoTarea = input.value.trim();
if (textoTarea) {
// Crear elementos
const nuevaTarea = document.createElement("li");
nuevaTarea.className = "tarea";
const textoElemento = document.createElement("span");
textoElemento.textContent = textoTarea;
const botonEliminar = document.createElement("button");
botonEliminar.textContent = "Eliminar";
botonEliminar.className = "eliminar";
// Añadir manejador de eventos al botón eliminar
botonEliminar.addEventListener("click", function() {
nuevaTarea.remove();
});
// Estructurar y añadir al DOM
nuevaTarea.appendChild(textoElemento);
nuevaTarea.appendChild(botonEliminar);
document.getElementById("lista-tareas").appendChild(nuevaTarea);
// Limpiar el input
input.value = "";
input.focus();
}
});
Ejemplo 2: Tabla dinámica desde datos JSON
// Datos de ejemplo
const personas = [
{ id: 1, nombre: "Ana", edad: 28, ciudad: "Madrid" },
{ id: 2, nombre: "Carlos", edad: 34, ciudad: "Barcelona" },
{ id: 3, nombre: "Elena", edad: 23, ciudad: "Valencia" }
];
function generarTabla(datos, contenedor) {
// Crear elementos de tabla
const tabla = document.createElement("table");
tabla.className = "tabla-datos";
// Crear encabezado
const thead = document.createElement("thead");
const filaCabecera = document.createElement("tr");
// Obtener las claves del primer objeto para las columnas
const columnas = Object.keys(datos[0]);
// Añadir cabeceras
columnas.forEach(columna => {
const th = document.createElement("th");
th.textContent = columna.charAt(0).toUpperCase() + columna.slice(1); // Capitalizar
filaCabecera.appendChild(th);
});
// Añadir columna adicional para acciones
const thAcciones = document.createElement("th");
thAcciones.textContent = "Acciones";
filaCabecera.appendChild(thAcciones);
thead.appendChild(filaCabecera);
tabla.appendChild(thead);
// Crear cuerpo de la tabla
const tbody = document.createElement("tbody");
// Añadir filas de datos
datos.forEach(objeto => {
const fila = document.createElement("tr");
fila.dataset.id = objeto.id;
// Añadir celdas con datos
columnas.forEach(columna => {
const celda = document.createElement("td");
celda.textContent = objeto[columna];
fila.appendChild(celda);
});
// Añadir celda con botón eliminar
const celdaAcciones = document.createElement("td");
const botonEliminar = document.createElement("button");
botonEliminar.textContent = "Eliminar";
botonEliminar.className = "btn-eliminar";
botonEliminar.addEventListener("click", function() {
fila.remove();
});
celdaAcciones.appendChild(botonEliminar);
fila.appendChild(celdaAcciones);
tbody.appendChild(fila);
});
tabla.appendChild(tbody);
// Limpiar el contenedor e insertar la tabla
const elementoContenedor = document.getElementById(contenedor);
elementoContenedor.innerHTML = "";
elementoContenedor.appendChild(tabla);
}
// Uso:
generarTabla(personas, "contenedor-tabla");
Ejemplo 3: Creación de una galería de imágenes
// Datos de ejemplo
const imagenes = [
{ url: "imagen1.jpg", titulo: "Paisaje de montaña" },
{ url: "imagen2.jpg", titulo: "Playa al atardecer" },
{ url: "imagen3.jpg", titulo: "Bosque en otoño" }
];
function crearGaleria(imagenes, contenedorId) {
const contenedor = document.getElementById(contenedorId);
contenedor.className = "galeria";
// Usar un fragmento para mejorar el rendimiento
const fragmento = document.createDocumentFragment();
imagenes.forEach(img => {
// Crear elemento contenedor para cada imagen
const tarjeta = document.createElement("div");
tarjeta.className = "tarjeta-imagen";
// Crear la imagen
const imagen = document.createElement("img");
imagen.src = img.url;
imagen.alt = img.titulo;
// Crear el título
const titulo = document.createElement("p");
titulo.className = "titulo-imagen";
titulo.textContent = img.titulo;
// Añadir eventos
tarjeta.addEventListener("click", function() {
mostrarImagenAmpliada(img.url, img.titulo);
});
// Estructurar la tarjeta
tarjeta.appendChild(imagen);
tarjeta.appendChild(titulo);
// Añadir al fragmento
fragmento.appendChild(tarjeta);
});
// Insertar todo en el contenedor
contenedor.appendChild(fragmento);
}
function mostrarImagenAmpliada(url, titulo) {
// Crear elementos para el modal
const modal = document.createElement("div");
modal.className = "modal";
const modalContenido = document.createElement("div");
modalContenido.className = "modal-contenido";
const imagen = document.createElement("img");
imagen.src = url;
imagen.alt = titulo;
const textoTitulo = document.createElement("h3");
textoTitulo.textContent = titulo;
const botonCerrar = document.createElement("button");
botonCerrar.textContent = "×";
botonCerrar.className = "cerrar-modal";
// Añadir evento para cerrar
botonCerrar.addEventListener("click", function() {
modal.remove();
});
// También cerrar al hacer clic fuera del contenido
modal.addEventListener("click", function(e) {
if (e.target === modal) {
modal.remove();
}
});
// Estructurar el modal
modalContenido.appendChild(botonCerrar);
modalContenido.appendChild(imagen);
modalContenido.appendChild(textoTitulo);
modal.appendChild(modalContenido);
// Añadir al body
document.body.appendChild(modal);
}
// Uso:
crearGaleria(imagenes, "contenedor-galeria");
Resumen
En este artículo hemos explorado las técnicas para crear, insertar, clonar, reemplazar y eliminar elementos del DOM. Hemos aprendido a utilizar métodos como createElement
, append
, appendChild
, insertBefore
, remove
y replaceWith
. También hemos visto cómo utilizar fragmentos de documento para mejorar el rendimiento en manipulaciones masivas.
Estas técnicas son fundamentales para crear interfaces dinámicas que respondan a las interacciones del usuario o a datos recibidos del servidor. En el próximo artículo, aprenderemos sobre los diferentes tipos de eventos en JavaScript, lo que nos permitirá responder a las acciones del usuario y crear experiencias interactivas más completas.