[CSS & JS]Personalizar input file

19:04 0 Comments A+ a-


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:


Código: HTML5
  1. <html>
  2.     <head>
  3.         <link href="input.css" rel="stylesheet" />
  4.         <script src="input.js"></script>
  5.     </head>
  6.     <body>
  7.         <center>
  8.             <form action="http://127.0.0.1:5000/upload" enctype="multipart/form-data" method="POST" id="frm_upload">
  9.                 <div id="upload">
  10.                     <input id="archivos" type="file" name="file[]" multiple="multiple" onchange="seleccionados();"/>
  11.                 </div>
  12.                 <span id="filename"></span>
  13.                 <p/>
  14.                 <input type="button" name="submit" value="Subir" onclick="subir();"/>
  15.             </form>
  16.         </center>
  17.     </body>
  18. </html>
  19.  

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
  1. input[type=file] {
  2.     opacity: 0;
  3.     width: 100%;
  4.     height: 100%;
  5. }
  6.  
  7. #upload {
  8.     background: url("https://cdn2.iconfinder.com/data/icons/internet/512/Upload-128.png") #111 center center no-repeat;
  9.     width: 150px;
  10.     border-radius: 5px;
  11.     height: 150px;
  12.     box-shadow: 0 0 5px #111;
  13. }

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
  1. //Creamos el array que usaremos para almacenar y enviar la informacion
  2. var ELEMENTOS = new Array();
  3.  
  4. function seleccionados() {
  5.     //Obtenemos el inputfile
  6.     var input = document.getElementById("archivos");
  7.     //Obtenemos los archivos
  8.     var archivos = input.files;
  9.     //Aca es donde mostraremos los elementos seleccionados
  10.     var elementos = document.getElementById("filename");
  11.        
  12.     //Limpiamos los elementos seleccionados anteriormente
  13.     elementos.innerHTML = " ";
  14.     ELEMENTOS = [];
  15.    
  16.     //Recorremos archivo por archivo
  17.     for (item=0; item< archivos.length; item++) {
  18.         //duplicamos el archivo seleccionado en el array elementos
  19.         ELEMENTOS[item] = archivos[item];
  20.         //Creamos un div donde mostramos el archivo seleccionado
  21.         crear_div("file", elementos, archivos[item].name);
  22.     }
  23. }
  24.  

La funcion crear_div: Esta funcion se encarga de crear un div, agregarle propiedades y luego incrustarlo en un elemento padre

Código: Javascript
  1. //funcion que crea un div
  2. function crear_div(clase, padre, informacion) {
  3.     //Escapamos la variable informacion para evitar posibles XSS
  4.     informacion = escape(informacion);
  5.     //Creamos el div
  6.     var div = document.createElement("div");
  7.     //Le agregamos al div sus propiedades
  8.     div.setAttribute("class", clase);
  9.     div.setAttribute("title", "click para eliminar");
  10.    
  11.     //en caso de hacer click en un elemento, lo elimina de la lista de los archivos a subir
  12.     div.onclick = function() {
  13.         var index = -1;
  14.         //eliminamos el archivo seleccionado de la lista
  15.         for (indice=0; indice < ELEMENTOS.length; indice++) {
  16.             //Buscamos el index del elemnto seleccionado para ser eliminado
  17.             if (ELEMENTOS[indice].name == unescape(informacion)) {
  18.                 index = indice;
  19.             }
  20.         }
  21.         if (index != -1) {
  22.             //removemos el elemento de la lista
  23.             ELEMENTOS.splice(index, 1);
  24.             padre.removeChild(div);
  25.         } else {
  26.             alert("No se pudo eliminar el elemento");
  27.         }
  28.        
  29.     }
  30.    
  31.     //Agregamos el div al padre
  32.     padre.appendChild(div);
  33.     div.innerHTML = informacion;
  34. }
  35.  


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
  1. .file {
  2.     background: #111;
  3.     display: inline-block;
  4.     margin: 5px;
  5.     color: #FFF;
  6.     line-height: 25px;
  7.     padding: 5px;
  8.     border-radius: 5px;
  9.     box-shadow: 0 0 5px #000;
  10. }

Y programar la función para subir los archivos al servidor:

Código: Javascript
  1. function subir() {
  2.     //creamos un nuevo formulario y lo llenamos con la información del array con los elementos a enviar
  3.     var formulario = new FormData();
  4.    
  5.     for (file=0; file < ELEMENTOS.length; file++) {
  6.         formulario.append("file[]", ELEMENTOS[file]);
  7.     }
  8.    
  9.     //obtenemos el action y method del formulario original
  10.     var frm = document.getElementById("frm_upload");
  11.     var metodo = frm.method.toUpperCase();
  12.     var action = frm.action;
  13.    
  14.     //enviamos el formulario
  15.     var request = new XMLHttpRequest;
  16.     request.open(metodo, action);
  17.     request.send(formulario);
  18. }

Y nuestro uploader está listo.