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:
