Volver
Ctrl+Space
◑
Copiar
Descargar
Restaurar
Ejecutar
Ctrl+Enter
<!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <title>Eventos en JS — Ejemplo 3</title> <style> body { font-family: Arial, sans-serif; padding: 20px; background: #fff; max-width: 620px; } h3 { margin: 22px 0 8px; font-size: 15px; color: #333; } .fila-input { display: flex; gap: 8px; margin-bottom: 14px; } input[type="text"] { flex: 1; padding: 9px 12px; border: 2px solid #ddd; border-radius: 6px; font-size: 14px; outline: none; transition: border-color 0.2s; } input[type="text"]:focus { border-color: #F7DF1E; } button { padding: 8px 16px; border: none; border-radius: 6px; font-weight: bold; cursor: pointer; font-size: 13px; } .btn-agregar { background: #F7DF1E; } .btn-agregar:hover { background: #e6cc00; } ul { list-style: none; padding: 0; margin: 0; } li { display: flex; align-items: center; gap: 10px; padding: 10px 14px; border: 1px solid #eee; border-radius: 8px; margin-bottom: 8px; background: #fafafa; transition: background 0.2s; } li.completada { background: #f0fdf4; border-color: #86efac; } li.completada .tarea-texto { text-decoration: line-through; color: #888; } .tarea-texto { flex: 1; font-size: 14px; } .btn-completar { background: #d1fae5; color: #059669; padding: 4px 10px; font-size: 12px; border-radius: 5px; } .btn-completar:hover { background: #a7f3d0; } .btn-borrar { background: #fee2e2; color: #dc2626; padding: 4px 10px; font-size: 12px; border-radius: 5px; } .btn-borrar:hover { background: #fca5a5; } .btn-subir { background: #e0e7ff; color: #4338ca; padding: 4px 8px; font-size: 12px; border-radius: 5px; } .btn-subir:hover { background: #c7d2fe; } .stats { font-size: 13px; color: #555; padding: 8px 0; border-top: 1px solid #eee; margin-top: 10px; } .vacío { text-align: center; color: #bbb; padding: 24px; font-size: 14px; } .log { background: #f9f9f9; border: 1px solid #eee; border-radius: 6px; padding: 8px 12px; font-family: monospace; font-size: 12px; max-height: 90px; overflow-y: auto; margin-top: 10px; } </style> </head> <body> <h2>Delegación de eventos — Lista de tareas</h2> <div class="fila-input"> <input type="text" id="inputTarea" placeholder="Nueva tarea..."> <button class="btn-agregar" id="btnAgregar">+ Agregar</button> </div> <ul id="lista"> <li class="vacia"><span class="vacío">No hay tareas. ¡Agregá una!</span></li> </ul> <div class="stats" id="stats"></div> <h3>Log de eventos (delegación en acción)</h3> <p style="font-size:12px;color:#888;">Un solo listener en <ul> captura todos los clics — incluso en elementos creados después.</p> <div class="log" id="log">Esperando clics...</div> <script> // Eventos en JavaScript - Ejemplo 3: Delegación de eventos const lista = document.getElementById("lista"); const inputTarea= document.getElementById("inputTarea"); let contador = 0; function actualizarStats() { const items = lista.querySelectorAll("li:not(.vacia)"); const completadas = lista.querySelectorAll("li.completada"); const stats = document.getElementById("stats"); if (items.length === 0) { stats.textContent = ""; return; } stats.textContent = `${items.length} tarea/s · ${completadas.length} completada/s · ${items.length - completadas.length} pendiente/s`; } function quitarVacia() { const vacia = lista.querySelector(".vacia"); if (vacia) vacia.remove(); } function mostrarVaciasSiNecesario() { if (lista.querySelectorAll("li:not(.vacia)").length === 0) { lista.innerHTML = `<li class="vacia"><span class="vacío">No hay tareas. ¡Agregá una!</span></li>`; } } function agregarLog(msg) { const log = document.getElementById("log"); const linea = document.createElement("div"); linea.textContent = msg; log.insertBefore(linea, log.firstChild); if (log.children.length > 5) log.lastChild.remove(); } function crearItem(texto) { contador++; const li = document.createElement("li"); li.dataset.id = contador; const span = document.createElement("span"); span.className = "tarea-texto"; span.textContent = texto; const btnC = document.createElement("button"); btnC.className = "btn-completar"; btnC.textContent = "✓"; btnC.dataset.accion = "completar"; const btnS = document.createElement("button"); btnS.className = "btn-subir"; btnS.textContent = "↑"; btnS.dataset.accion = "subir"; const btnB = document.createElement("button"); btnB.className = "btn-borrar"; btnB.textContent = "✕"; btnB.dataset.accion = "borrar"; li.append(span, btnC, btnS, btnB); return li; } function agregar() { const texto = inputTarea.value.trim(); if (!texto) { inputTarea.focus(); return; } quitarVacia(); lista.appendChild(crearItem(texto)); inputTarea.value = ""; inputTarea.focus(); actualizarStats(); agregarLog(`+ Agregada: "${texto}"`); } // ── UN SOLO LISTENER para todos los botones ─────────────────────────── // Esto es delegación: el listener está en <ul>, no en cada botón. // Funciona para elementos creados dinámicamente también. lista.addEventListener("click", (e) => { const accion = e.target.dataset.accion; if (!accion) return; const li = e.target.closest("li"); const texto = li.querySelector(".tarea-texto").textContent; if (accion === "completar") { li.classList.toggle("completada"); const estado = li.classList.contains("completada") ? "completada" : "pendiente"; agregarLog(`✓ "${texto}" → ${estado}`); } if (accion === "borrar") { li.remove(); mostrarVaciasSiNecesario(); agregarLog(`✕ Borrada: "${texto}"`); } if (accion === "subir") { const anterior = li.previousElementSibling; if (anterior && !anterior.classList.contains("vacia")) { lista.insertBefore(li, anterior); agregarLog(`↑ Subida: "${texto}"`); } } actualizarStats(); }); // ── Agregar con botón y con Enter ───────────────────────────────────── document.getElementById("btnAgregar").addEventListener("click", agregar); inputTarea.addEventListener("keydown", (e) => { if (e.key === "Enter") agregar(); }); // Tareas iniciales de ejemplo ["Aprender delegación de eventos", "Practicar con el editor", "Leer el tutorial de DOM"].forEach(t => { quitarVacia(); lista.appendChild(crearItem(t)); }); actualizarStats(); </script> </body> </html>