[CSS & JS]Personalizar input file
Los que alguna vez jugueteamos con el diseño web, muy seguramente nos encontramos con el problema de personalizar los input file. Inteentaré mostrar la forma en que logré personalizar los input file usando sólo CSS, JS, y el DOM de una manera sencilla. Que además nos permite eliminar archivos que ya estan en la lista para ser subidos al servidor.
La idea es convertir esto:
en esto:
en esto:
Código: HTML5
- <html>
- <head>
- <link href="input.css" rel="stylesheet" />
- </head>
- <body>
- <center>
- <form action="http://127.0.0.1:5000/upload" enctype="multipart/form-data" method="POST" id="frm_upload">
- <div id="upload">
- <input id="archivos" type="file" name="file[]" multiple="multiple" onchange="seleccionados();"/>
- </div>
- <p/>
- <input type="button" name="submit" value="Subir" onclick="subir();"/>
- </form>
- </center>
- </body>
- </html>
Para eso, vamos a usar un formulario normal, estructurado así:
un div con id "upload" dentro del cual meteremos el input file; es el div que moldearemos para que tome la forma que nuestro upload tenga.
un input file configurado para seleccionar multiples archivos. Cuando se selecciona un archivo (evento onchange) llama a la función seleccionados
un span con id "filename" que es donde mostraremos los archivos seleccionados
un input button que se encargara cuando hagamos click sobre el de enviar el formulario.
El css (input.css):
Código: CSS
- input[type=file] {
- opacity: 0;
- width: 100%;
- height: 100%;
- }
- #upload {
- background: url("https://cdn2.iconfinder.com/data/icons/internet/512/Upload-128.png") #111 center center no-repeat;
- width: 150px;
- border-radius: 5px;
- height: 150px;
- box-shadow: 0 0 5px #111;
- }
Este sencillo CSS simplemente hace invisible el input file (opacity: 0) y le da un ancho y alto de 100% para que ocupe la totalidad del div (upload)
en el bloque #upload, damos la apariencia que queremos que tengo nuestro upload agrgando un simple background, una sombra y unas dimensiones (150x150).
Hasta ahora, nuestro upload se ve así:
Si lo clickeamos, nos abre la ventana para seleccionar los archivos, pero una vez seleccionados, NO LOS MUESTRA. Así que ahora vamos a codear el JS:
El JS (input.js): Los navegadores no nos dejan modificar los datos de los input file, pero si que nos permite juguetear un poco con los datos. Así que lo que haremos sera obtener la lista de los elementos seleccionados y la guardaremos en un array que podremos modificar (ara eliminar los elemento que no queremos subir) y a la hora de enviar el formulario al servidor, lo que haremos es simular un formulario que llenaremos con la informacion del array y lo enviamos al servidor.
La función seleccionados:
Código: Javascript
- //Creamos el array que usaremos para almacenar y enviar la informacion
- var ELEMENTOS = new Array();
- function seleccionados() {
- //Obtenemos el inputfile
- var input = document.getElementById("archivos");
- //Obtenemos los archivos
- var archivos = input.files;
- //Aca es donde mostraremos los elementos seleccionados
- var elementos = document.getElementById("filename");
- //Limpiamos los elementos seleccionados anteriormente
- elementos.innerHTML = " ";
- ELEMENTOS = [];
- //Recorremos archivo por archivo
- for (item=0; item< archivos.length; item++) {
- //duplicamos el archivo seleccionado en el array elementos
- ELEMENTOS[item] = archivos[item];
- //Creamos un div donde mostramos el archivo seleccionado
- crear_div("file", elementos, archivos[item].name);
- }
- }
La funcion crear_div: Esta funcion se encarga de crear un div, agregarle propiedades y luego incrustarlo en un elemento padre
Código: Javascript
- //funcion que crea un div
- function crear_div(clase, padre, informacion) {
- //Escapamos la variable informacion para evitar posibles XSS
- informacion = escape(informacion);
- //Creamos el div
- var div = document.createElement("div");
- //Le agregamos al div sus propiedades
- div.setAttribute("class", clase);
- div.setAttribute("title", "click para eliminar");
- //en caso de hacer click en un elemento, lo elimina de la lista de los archivos a subir
- div.onclick = function() {
- var index = -1;
- //eliminamos el archivo seleccionado de la lista
- for (indice=0; indice < ELEMENTOS.length; indice++) {
- //Buscamos el index del elemnto seleccionado para ser eliminado
- if (ELEMENTOS[indice].name == unescape(informacion)) {
- index = indice;
- }
- }
- if (index != -1) {
- //removemos el elemento de la lista
- ELEMENTOS.splice(index, 1);
- padre.removeChild(div);
- } else {
- alert("No se pudo eliminar el elemento");
- }
- }
- //Agregamos el div al padre
- padre.appendChild(div);
- div.innerHTML = informacion;
- }
Hasta ahora, nuestro upload se ve así.
Sólo nos resta darle un estilo a los div que contienen el nombre de los archivos seleccionados (que tienen la clase file):
Código: CSS
- .file {
- background: #111;
- display: inline-block;
- margin: 5px;
- color: #FFF;
- line-height: 25px;
- padding: 5px;
- border-radius: 5px;
- box-shadow: 0 0 5px #000;
- }
Y programar la función para subir los archivos al servidor:
Código: Javascript
- function subir() {
- //creamos un nuevo formulario y lo llenamos con la información del array con los elementos a enviar
- var formulario = new FormData();
- for (file=0; file < ELEMENTOS.length; file++) {
- formulario.append("file[]", ELEMENTOS[file]);
- }
- //obtenemos el action y method del formulario original
- var frm = document.getElementById("frm_upload");
- var metodo = frm.method.toUpperCase();
- var action = frm.action;
- //enviamos el formulario
- var request = new XMLHttpRequest;
- request.open(metodo, action);
- request.send(formulario);
- }
Y nuestro uploader está listo.