Mini formulario de carga de archivos AJAX

En este tutorial, vamos a crear un formulario de carga de archivos AJAX, que permitirá a los visitantes cargar archivos desde sus navegadores con arrastrar y soltar o seleccionándolos individualmente. Para este propósito, combinaremos el potente complemento jQuery File Upload con el ingenioso jQuery Knob para presentar una elegante interfaz impulsada por CSS3/JS.

El HTML

Como de costumbre, comenzaremos con un documento HTML5 básico:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="utf-8"/>
        <title>Mini Ajax File Upload Form</title>

        <!-- Google web fonts -->
        <link href="http://fonts.googleapis.com/css?family=PT+Sans+Narrow:400,700" rel='stylesheet' />

        <!-- The main CSS file -->
        <link href="assets/css/style.css" rel="stylesheet" />
    </head>

    <body>

        <form id="upload" method="post" action="upload.php" enctype="multipart/form-data">
            <div id="drop">
                Drop Here

                <a>Browse</a>
                <input type="file" name="upl" multiple />
            </div>

            <ul>
                <!-- The file uploads will be shown here -->
            </ul>

        </form>

        <!-- JavaScript Includes -->
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
        <script src="assets/js/jquery.knob.js"></script>

        <!-- jQuery File Upload Dependencies -->
        <script src="assets/js/jquery.ui.widget.js"></script>
        <script src="assets/js/jquery.iframe-transport.js"></script>
        <script src="assets/js/jquery.fileupload.js"></script>

        <!-- Our main JS file -->
        <script src="assets/js/script.js"></script>

    </body>
</html>

En el encabezado del documento, he incluido dos fuentes de Google Webfonts y, antes de la etiqueta de cierre , puede ver varias bibliotecas de JavaScript. Estas son la biblioteca jQuery, el complemento jQuery Knob y las dependencias para el complemento jQuery File Upload.

El elemento principal de la página es #upload forma. En su interior está la #gota div (que acepta cargas de arrastrar y soltar) y una lista desordenada. Esta lista contendrá un elemento li para cada uno de los archivos transferidos. Puede ver el marcado generado para la carga de un archivo a continuación:

<li class="working">
    <input type="text" value="0" data-width="48" data-height="48" data-fgColor="#0788a5" data-readOnly="1" data-bgColor="#3e4043" />
    <p>Sunset.jpg <i>145 KB</i></p>
    <span></span>
</li>

El elemento de entrada en el fragmento anterior está oculto con CSS. Su único propósito es inicializar el complemento jQuery Knob, que generará un bonito control de perilla basado en lienzo. La entrada tiene un número de datos-* atributos que modifican la apariencia de la perilla. Más tarde, cuando escuchemos el progreso de carga del archivo, actualizaremos el valor de esta entrada, lo que hará que la perilla se vuelva a dibujar. El lapso sostiene el ícono a la derecha; esto puede ser una marca de verificación o una cruz roja.

El código jQuery

Hay dos formas en que un visitante puede cargar archivos con este formulario:

  • Soltándolos en el #drop div (en todos los navegadores excepto IE);
  • Haciendo clic en el botón de exploración. Esto simulará un clic en la entrada del archivo oculto, lo que abrirá la ventana de exploración de archivos del sistema. Observe que la entrada del archivo tiene el múltiple conjunto de parámetros, que permitirá seleccionar más de un archivo en un momento dado (¡aunque los archivos se seguirán cargando individualmente!).

El comportamiento predeterminado del complemento es colocar los archivos en una cola, pero haremos que los archivos se carguen automáticamente cuando se sueltan/seleccionan, lo que hará que la experiencia sea más sencilla. Puede ver el JS a continuación:

activos/js/script.js

$(function(){

    var ul = $('#upload ul');

    $('#drop a').click(function(){
        // Simulate a click on the file input button
        // to show the file browser dialog
        $(this).parent().find('input').click();
    });

    // Initialize the jQuery File Upload plugin
    $('#upload').fileupload({

        // This element will accept file drag/drop uploading
        dropZone: $('#drop'),

        // This function is called when a file is added to the queue;
        // either via the browse button, or via drag/drop:
        add: function (e, data) {

            var tpl = $('<li class="working"><input type="text" value="0" data-width="48" data-height="48"'+
                ' data-fgColor="#0788a5" data-readOnly="1" data-bgColor="#3e4043" /><p></p><span></span></li>');

            // Append the file name and file size
            tpl.find('p').text(data.files[0].name)
                         .append('<i>' + formatFileSize(data.files[0].size) + '</i>');

            // Add the HTML to the UL element
            data.context = tpl.appendTo(ul);

            // Initialize the knob plugin
            tpl.find('input').knob();

            // Listen for clicks on the cancel icon
            tpl.find('span').click(function(){

                if(tpl.hasClass('working')){
                    jqXHR.abort();
                }

                tpl.fadeOut(function(){
                    tpl.remove();
                });

            });

            // Automatically upload the file once it is added to the queue
            var jqXHR = data.submit();
        },

        progress: function(e, data){

            // Calculate the completion percentage of the upload
            var progress = parseInt(data.loaded / data.total * 100, 10);

            // Update the hidden input field and trigger a change
            // so that the jQuery knob plugin knows to update the dial
            data.context.find('input').val(progress).change();

            if(progress == 100){
                data.context.removeClass('working');
            }
        },

        fail:function(e, data){
            // Something has gone wrong!
            data.context.addClass('error');
        }

    });

    // Prevent the default action when a file is dropped on the window
    $(document).on('drop dragover', function (e) {
        e.preventDefault();
    });

    // Helper function that formats the file sizes
    function formatFileSize(bytes) {
        if (typeof bytes !== 'number') {
            return '';
        }

        if (bytes >= 1000000000) {
            return (bytes / 1000000000).toFixed(2) + ' GB';
        }

        if (bytes >= 1000000) {
            return (bytes / 1000000).toFixed(2) + ' MB';
        }

        return (bytes / 1000).toFixed(2) + ' KB';
    }

});

La biblioteca jQuery File Upload viene con su propio diseño impulsado por jQuery UI que puede usar de inmediato. Sin embargo, debido a que necesitamos una interfaz completamente personalizada, utilizaremos la versión básica del complemento, que no incluye una interfaz. Para que funcione, estamos pasando una serie de opciones de configuración/devoluciones de llamada. En el código anterior, estos son:

  • Zona de caída - Esta propiedad contiene el selector jQuery del elemento que actuará como destino de colocación. Los archivos que se suelten se agregarán a la cola de carga.
  • añadir - Esta función de devolución de llamada se llama cada vez que se agrega un archivo a la cola. Dentro de él, creamos el marcado HTML que representará el archivo, lo agregamos a la UL y activamos el data.submit() método. Esto hará que el archivo agregado se cargue directamente sin esperar.
  • progreso - Esta devolución de llamada la ejecuta el complemento cada 100 ms (configurable). El segundo argumento (el atributo de datos) contiene el tamaño del archivo y cuántos bytes se han transferido. Esto nos permite calcular un porcentaje y, posteriormente, actualizar el elemento de entrada oculto, que a su vez actualiza la perilla.
  • fallo - Esta función de devolución de llamada se ejecuta si hay un problema con su script PHP. Lo más probable es que esto signifique que upload.php falta o arroja algún tipo de error (use el inspector de su navegador web para depurar cualquier problema potencial aquí).

El data.context La propiedad se conserva entre las llamadas de método del complemento. De esta manera, sabemos qué elemento de LI debemos actualizar en los eventos de progreso y falla.

La secuencia de comandos PHP

jQuery File Upload también viene con un poderoso script PHP para manejar la carga de archivos que puede colocar en su servidor, pero para este tutorial, crearemos el nuestro. Las cargas de archivos enviadas por el complemento son prácticamente las mismas que una carga de formulario regular:puede acceder a la información sobre las cargas a través de la matriz $_FILES:

<?php

// A list of permitted file extensions
$allowed = array('png', 'jpg', 'gif','zip');

if(isset($_FILES['upl']) && $_FILES['upl']['error'] == 0){

    $extension = pathinfo($_FILES['upl']['name'], PATHINFO_EXTENSION);

    if(!in_array(strtolower($extension), $allowed)){
        echo '{"status":"error"}';
        exit;
    }

    if(move_uploaded_file($_FILES['upl']['tmp_name'], 'uploads/'.$_FILES['upl']['name'])){
        echo '{"status":"success"}';
        exit;
    }
}

echo '{"status":"error"}';
exit;

Como mencioné más atrás, aunque podemos seleccionar un montón de archivos a la vez, se cargan uno por uno. Esto hace que sea aún más fácil manejarlos con nuestro script PHP. Actualmente, los archivos simplemente se mueven a la carpeta de carga, pero puede ampliarla agregando autenticación o creando registros en su base de datos.

¡Hemos terminado!

¡Espero que encuentre útil este formulario de carga de archivos ajax! Si tienes sugerencias o preguntas, déjalas en nuestra área de comentarios.

Recursos y lecturas adicionales

  • La página de inicio del complemento jQuery Knob
  • La página de github del complemento jQuery File Upload
  • API de carga de archivos jQuery
  • Opciones de carga de archivos jQuery
  • Preguntas frecuentes sobre la carga de archivos jQuery
  • Cómo mejorar la zona de colocación con efectos de arrastre
  • Toma de Dribbble en la que se inspiró el diseño de este tutorial