En este capítulo vamos a hacer que nuestro cargador de archivos sea DRAG AND DROP, para lo que vamos a tener que hacer ciertos cambios en los elementos HTML. Vamos a trabajar con el API DRAG AND DROP, donde podemos encontrar toda la información de la misma en MDN.
Nosotros a cualquier elemento en el HTML le podemos dotar de las características de DRAG AND DROP. En este capítulo no utilizaremos la delegación de eventos porque el único elemento que va a ser zona de interacción activa va a ser la drop-zone, por lo que los eventos se los vamos a asignar directamente a la drop-zone.
Hay varios eventos de DRAG AND DROP, en este capítulo utilizaremos 3:
- dragover: el evento cuando estamos sobre el elemento. Es el evento que se va a estar ejecutando mientras tengamos un archivo sobre la zona que es DRAG AND DROP.
- dragleave (es como el mouseout): el evento cuando sales de la zona arrastrable y soltable.
- drop: el evento cuando soltamos el archivo. Es realmente el evento que hace que los archivos suban al servidor.
Unicamente vamos a modificar el archivo uploader.html, al que le vamos a llamar ahora uploader-drag-and-drop.html, cuya sintaxis es la siguiente.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Uploader Drag and Drop con AJAX</title> <style> html { box-sizing: border-box; font-family: sans-serif; font-size: 16px; } *, *::after, *::before { box-sizing: inherit; } body { margin: 0; } main { display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; min-height: 100vh; } progress { margin-top: 1rem; } .drop-zone { margin-left: auto; margin-right: auto; border: thin dotted #000; width: 80%; height: 40vh; display: flex; justify-content: center; align-items: center; text-align: center; } .drop-zone.is-active { border: thick dashed #000; background-color: rgba(0, 128, 0, 0.5); animation: pulse 1.5s infinite; animation-timing-function: linear; } @keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.1); } } </style> </head> <body> <main> <article class="drop-zone"> <p>Arrastra y suelta tus archivos...</p> </article> </main> <script> const d = document, $main = d.querySelector("main"), $dropZone = d.querySelector(".drop-zone"); // Creamos función que mediante AJAX permita subir la carga de archivos // Esta función se ejecutará por cada archivo que reciba el input const uploader = (file) => { const xhr = new XMLHttpRequest(), formData = new FormData(); formData.append("file", file); xhr.addEventListener("readystatechange", (e) => { if (xhr.readyState !== 4) return; if (xhr.status >= 200 && xhr.status < 300) { let json = JSON.parse(xhr.responseText); console.log(json); } else { let message = xhr.statusText || "Ocurrió un error"; console.log(`Error ${xhr.status}: ${message}`); } }); xhr.open("POST", "uploader.php"); xhr.setRequestHeader("enc-type", "multipart/form-data"); xhr.send(formData); }; const progressUpload = (file) => { const $progress = d.createElement("progress"), $span = d.createElement("span"); $progress.value = 0; $progress.max = 100; $main.insertAdjacentElement("beforeend", $progress); $main.insertAdjacentElement("beforeend", $span); const fileReader = new FileReader(); fileReader.readAsDataURL(file); fileReader.addEventListener("progress", (e) => { let progress = parseInt((e.loaded * 100) / e.total); $progress.value = progress; $span.innerHTML = `<b>${file.name} - ${progress}%</b>`; }); fileReader.addEventListener("loadend", (e) => { uploader(file); setTimeout(() => { $main.removeChild($progress); $main.removeChild($span); }, 3000); }); }; $dropZone.addEventListener("dragover", (e) => { e.preventDefault(); e.stopPropagation(); e.target.classList.add("is-active"); }); $dropZone.addEventListener("dragleave", (e) => { e.preventDefault(); e.stopPropagation(); e.target.classList.remove("is-active"); }); $dropZone.addEventListener("drop", (e) => { e.preventDefault(); e.stopPropagation(); const files = Array.from(e.dataTransfer.files); files.forEach((el) => progressUpload(el)); e.target.classList.remove("is-active"); }); </script> </body> </html>
El ejercicio completo está en el siguiente ZIP: