¿Cómo puedo crear una animación "Espere, cargando ..." usando jQuery?

585

Me gustaría colocar una animación de círculo giratorio "espere, cargando" en mi sitio. ¿Cómo debo lograr esto usando jQuery?

thedp
fuente

Respuestas:

1211

Podrías hacer esto de diferentes maneras. Podría ser un estado sutil como pequeño en la página que dice "Cargando ...", o tan alto como un elemento completo que atenúa la página mientras se cargan los nuevos datos. El enfoque que estoy tomando a continuación le mostrará cómo lograr ambos métodos.

La puesta en marcha

Comencemos por obtener una buena animación de "carga" de http://ajaxload.info que usaréingrese la descripción de la imagen aquí

Creemos un elemento que podamos mostrar / ocultar cada vez que hagamos una solicitud ajax:

<div class="modal"><!-- Place at bottom of page --></div>

El CSS

A continuación, demos un poco de estilo:

/* Start by setting display:none to make this hidden.
   Then we position it in relation to the viewport window
   with position:fixed. Width, height, top and left speak
   for themselves. Background we set to 80% white with
   our animation centered, and no-repeating */
.modal {
    display:    none;
    position:   fixed;
    z-index:    1000;
    top:        0;
    left:       0;
    height:     100%;
    width:      100%;
    background: rgba( 255, 255, 255, .8 ) 
                url('http://i.stack.imgur.com/FhHRx.gif') 
                50% 50% 
                no-repeat;
}

/* When the body has the loading class, we turn
   the scrollbar off with overflow:hidden */
body.loading .modal {
    overflow: hidden;   
}

/* Anytime the body has the loading class, our
   modal element will be visible */
body.loading .modal {
    display: block;
}

Y finalmente, el jQuery

Muy bien, a la jQuery. La siguiente parte es realmente muy simple:

$body = $("body");

$(document).on({
    ajaxStart: function() { $body.addClass("loading");    },
     ajaxStop: function() { $body.removeClass("loading"); }    
});

¡Eso es! Adjuntamos algunos eventos al elemento del cuerpo cada vez que se disparan los eventos ajaxStarto ajaxStop. Cuando comienza un evento ajax, agregamos la clase "cargando" al cuerpo. y cuando se realizan los eventos, eliminamos la clase "cargando" del cuerpo.

Véalo en acción: http://jsfiddle.net/VpDUG/4952/

Sampson
fuente
8
Esta es la solución más profunda, aunque le recomiendo que use un complemento de centrado que centre el precargador alrededor de un elemento de página ( es decir, cuerpo, #elemento o .elemento )
Corey Ballou
2
Esa sería una buena adición, Cballou. Simplemente estaba tratando de mantener la información minimizada, pero como usted señala, ciertamente se puede mejorar.
Sampson
99
¡Tuve que usar .bind () en lugar de .on () ya que estamos usando jQuery 1.5.1!
renegadeMind
39
Recomiendo usar el complemento que se conecta a los complementos para asegurarse de que todos estén enchufados.
contactmatt
15
Nota: A partir de jQuery 1.8, el método .ajaxStop()y .ajaxStart()solo debe adjuntarse al documento. docs
balexandre
215

En cuanto a la imagen de carga real, consulte este sitio para ver un montón de opciones.

En cuanto a mostrar un DIV con esta imagen cuando comienza una solicitud, tiene algunas opciones:

A) Mostrar y ocultar manualmente la imagen:

$('#form').submit(function() {
    $('#wait').show();
    $.post('/whatever.php', function() {
        $('#wait').hide();
    });
    return false;
});

B) Use ajaxStart y ajaxComplete :

$('#wait').ajaxStart(function() {
    $(this).show();
}).ajaxComplete(function() {
    $(this).hide();
});

Con esto, el elemento mostrará / ocultará cualquier solicitud. Puede ser bueno o malo, según la necesidad.

C) Utilice devoluciones de llamada individuales para una solicitud particular:

$('#form').submit(function() {
    $.ajax({
        url: '/whatever.php',
        beforeSend: function() { $('#wait').show(); },
        complete: function() { $('#wait').hide(); }
    });
    return false;
});
Paolo Bergantino
fuente
44
Algo a tener en cuenta: si no puede modificar el HTML para agregar el elemento img de carga, puede hacerlo como una imagen de fondo en el botón usando CSS, por ejemplo input.loading-gif {background: url ('images / loading.gif') ;} y luego aplique la clase con jQuery, por ejemplo, $ ('# mybutton'). addClass ('loading-gif'); El único inconveniente es que esto solo solicitará el gif cuando se haga clic en el botón Enviar, que normalmente es demasiado tarde, por lo que debe almacenarlo previamente en caché, lo que es fácil con jQuery, por ejemplo (nueva Imagen ()). Src = "images /loading.gif ";
jackocnr
44
Este sitio tiene una selección más grande y más agradable de cargadores con más opciones de personalización preloaders.net
rorypicko
FYI: se fusionó de stackoverflow.com/questions/750358/…
Shog9
Buena solución, pero cuando llamo a show () después de hide () no funciona . Encontré una solución que es cambiar show () y hide () para alternar (). Esperando que pueda ayudar a alguien a tener el mismo problema que yo. Además, probé la solución C) y fundé beforeSend no funciona en asíncrono. Entonces, sugerí llamar a show () por encima de $ .ajax para que funcione correctamente.
瑲 瑲
Muchas gracias @Paolo. Personalmente, me gustó su respuesta que la aceptada por la mayoría de los usuarios. Por lo tanto, +1 a ti desde mi lado.
Ashok Kumar
113

Junto con lo que Jonathan y Samir sugirieron (¡ambas respuestas excelentes por cierto!), JQuery tiene algunos eventos incorporados que se dispararán para ti cuando realices una solicitud de ajax.

Ahí está el ajaxStartevento

Muestra un mensaje de carga cada vez que se inicia una solicitud AJAX (y ninguna está activa).

... y es hermano, el ajaxStopevento

Adjunte una función para que se ejecute siempre que todas las solicitudes de AJAX hayan finalizado. Este es un evento Ajax.

Juntos, hacen una excelente manera de mostrar un mensaje de progreso cuando ocurre cualquier actividad de ajax en cualquier lugar de la página.

HTML:

<div id="loading">
  <p><img src="loading.gif" /> Please Wait</p>
</div>

Guión:

$(document).ajaxStart(function(){
    $('#loading').show();
 }).ajaxStop(function(){
    $('#loading').hide();
 });
Dan F
fuente
Esto está desactualizado, a partir de 1.8.0, .ajaxStartsolo se puede adjuntar al documento, es decir. $(document).ajaxStart(function(){}).
Jonno_FTW
2
@Jonno_FTW arreglado. Ejército de reserva. Antigua pregunta y respuesta que ha sido reemplazada por las ediciones de Jonathan Sampson a su pregunta, pero bueno para mantenerla actualizada de todos modos
Dan F
3
La respuesta de Jonathan fue muy profunda, pero para mí fue la mejor por su simplicidad.
Ojonugwa Jude Ochalifu
19

Puede tomar un GIF animado de un círculo giratorio de Ajaxload ; pegarlo en algún lugar de la jerarquía de archivos de su sitio web. Luego solo necesita agregar un elemento HTML con el código correcto y eliminarlo cuando haya terminado. Esto es bastante simple:

function showLoadingImage() {
    $('#yourParentElement').append('<div id="loading-image"><img src="path/to/loading.gif" alt="Loading..." /></div>');
}

function hideLoadingImage() {
    $('#loading-image').remove();
}

Entonces solo necesita usar estos métodos en su llamada AJAX:

$.load(
     'http://example.com/myurl',
     { 'random': 'data': 1: 2, 'dwarfs': 7},
     function (responseText, textStatus, XMLHttpRequest) {
         hideLoadingImage();
     }
);

// this will be run immediately after the AJAX call has been made,
// not when it completes.
showLoadingImage();

Esto tiene algunas advertencias: en primer lugar, si tiene dos o más lugares donde se puede mostrar la imagen de carga, tendrá que mantener un registro de cuántas llamadas se están ejecutando a la vez de alguna manera, y solo se ocultará cuando estén todo listo. Esto se puede hacer usando un contador simple, que debería funcionar para casi todos los casos.

En segundo lugar, esto solo ocultará la imagen de carga en una llamada AJAX exitosa. Para manejar los estados de error, tendrá que investigar $.ajax, que es más complejo que $.load, $.gety similares, pero también mucho más flexible.

Samir Talwar
fuente
2
Gracias por la respuesta. Pero dime, ¿por qué necesito usar AJAX? ¿No puedo simplemente rastrearlo todo en la página misma?
thedp
¿Qué es exactamente lo que quieres rastrear? A menos que esté solicitando información después de que la página se haya cargado (y AJAX es prácticamente la única forma de hacerlo sin usar un complemento), ¿por qué necesitaría una imagen de "carga"?
Samir Talwar
Samir Talwar: una aplicación pesada de JavaScript en realidad. Gracias, entiendo la idea.
thedp
Comprensible. En ese caso, solo llame showLoadingImageantes de comenzar y hideLoadingImagedespués de terminar. Debería ser bastante simple. Sin embargo, es posible que deba pegar algún tipo de setTimeoutllamada para asegurarse de que el navegador realmente muestre la nueva <img>etiqueta. He visto un par de casos en los que no molesta hasta que JavaScript ha terminado de ejecutarse.
Samir Talwar
16

La excelente solución de Jonathon se rompe en IE8 (la animación no se muestra en absoluto). Para solucionar esto, cambie el CSS a:

.modal {
display:    none;
position:   fixed;
z-index:    1000;
top:        0;
left:       0;
height:     100%;
width:      100%;
background: rgba( 255, 255, 255, .8 ) 
            url('http://i.stack.imgur.com/FhHRx.gif') 
            50% 50% 
            no-repeat;
opacity: 0.80;
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity = 80);
filter: alpha(opacity = 80)};
Ben Power
fuente
2
Editado porque las múltiples líneas 'background-' no funcionaron, pero la declaración de fondo única funciona correctamente.
Maurice Flanagan
7

jQuery proporciona enlaces de eventos para cuando las solicitudes AJAX comienzan y finalizan. Puede conectarlos para mostrar su cargador.

Por ejemplo, cree el siguiente div:

<div id="spinner">
  <img src="images/spinner.gif" alt="Loading" />
</div>

Configúrelo display: noneen sus hojas de estilo. Puedes peinarlo como quieras. Puede generar una buena imagen de carga en Ajaxload.info , si lo desea.

Luego, puede usar algo como lo siguiente para que se muestre automáticamente al enviar solicitudes de Ajax:

$(document).ready(function () {

    $('#spinner').bind("ajaxSend", function() {
        $(this).show();
    }).bind("ajaxComplete", function() {
        $(this).hide();
    });

});

Simplemente agregue este bloque de Javascript al final de su página antes de cerrar su etiqueta de cuerpo o donde mejor le parezca.

Ahora, cada vez que envíe solicitudes Ajax, #spinnerse mostrará el div. Cuando se complete la solicitud, se ocultará nuevamente.

Veeti
fuente
¿Alguien puede explicar qué tiene que ver AJAX con esto? ¿No puedo simplemente administrar todo esto dentro de la página sin acceder al servidor con AJAX ... o me falta algo aquí? Gracias.
thedp
44
Ah, como entendí, quería que se mostrara una imagen de carga cada vez que realizaba solicitudes AJAX. Si simplemente desea que se muestre una animación "espere, cargando ..." hasta que la página se haya cargado por completo, puede tener un div de carga en la página y luego ocultarlo en su bloque $ (document) .ready.
Veeti
7

Si está utilizando Turbolinks With Rails, esta es mi solución:

Este es el CoffeeScript

$(window).on 'page:fetch', ->
  $('body').append("<div class='modal'></div>")
  $('body').addClass("loading")

$(window).on 'page:change', ->
  $('body').removeClass("loading")

Este es el CSS de SASS basado en la primera respuesta excelente de Jonathan Sampson

# loader.css.scss

.modal {
    display:    none;
    position:   fixed;
    z-index:    1000;
    top:        0;
    left:       0;
    height:     100%;
    width:      100%;
    background: rgba( 255, 255, 255, 0.4)
            asset-url('ajax-loader.gif', image)
            50% 50% 
            no-repeat;
}
body.loading {
    overflow: hidden;   
}

body.loading .modal {
    display: block;
}
Fred
fuente
6

Como Mark H dijo que el blockUI es el camino.

Ex.:

<script type="text/javascript" src="javascript/jquery/jquery.blockUI.js"></script>
<script>
// unblock when ajax activity stops
$(document).ajaxStop($.unblockUI); 

$("#downloadButton").click(function() {

    $("#dialog").dialog({
        width:"390px",
        modal:true,
        buttons: {
            "OK, AGUARDO O E-MAIL!":  function() {
                $.blockUI({ message: '<img src="img/ajax-loader.gif" />' });
                send();
            }
        }
    });
});

function send() {
    $.ajax({
        url: "download-enviar.do",          
        type: "POST",
        blablabla
    });
}
</script>

Obs .: Obtuve el ajax-loader.gif en http://www.ajaxload.info/

bpedroso
fuente
FYI: se fusionó de stackoverflow.com/questions/750358/…
Shog9
6

Con el debido respeto a otras publicaciones, tiene aquí una solución muy simple, usando CSS3 y jQuery, sin usar más recursos externos ni archivos.

$('#submit').click(function(){
  $(this).addClass('button_loader').attr("value","");
  window.setTimeout(function(){
    $('#submit').removeClass('button_loader').attr("value","\u2713");
    $('#submit').prop('disabled', true);
  }, 3000);
});
#submit:focus{
  outline:none;
  outline-offset: none;
}

.button {
    display: inline-block;
    padding: 6px 12px;
    margin: 20px 8px;
    font-size: 14px;
    font-weight: 400;
    line-height: 1.42857143;
    text-align: center;
    white-space: nowrap;
    vertical-align: middle;
    -ms-touch-action: manipulation;
    cursor: pointer;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    background-image: none;
    border: 2px solid transparent;
    border-radius: 5px;
    color: #000;
    background-color: #b2b2b2;
    border-color: #969696;
}

.button_loader {
  background-color: transparent;
  border: 4px solid #f3f3f3;
  border-radius: 50%;
  border-top: 4px solid #969696;
  border-bottom: 4px solid #969696;
  width: 35px;
  height: 35px;
  -webkit-animation: spin 0.8s linear infinite;
  animation: spin 0.8s linear infinite;
}

@-webkit-keyframes spin {
  0% { -webkit-transform: rotate(0deg); }
  99% { -webkit-transform: rotate(360deg); }
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  99% { transform: rotate(360deg); }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="submit" class="button" type="submit" value="Submit" />

João Pimentel Ferreira
fuente
5

Esto haría que los botones desaparecieran, luego una animación de "carga" aparecería en su lugar y finalmente solo mostraría un mensaje de éxito.

$(function(){
    $('#submit').click(function(){
        $('#submit').hide();
        $("#form .buttons").append('<img src="assets/img/loading.gif" alt="Loading..." id="loading" />');
        $.post("sendmail.php",
                {emailFrom: nameVal, subject: subjectVal, message: messageVal},
                function(data){
                    jQuery("#form").slideUp("normal", function() {                 
                        $("#form").before('<h1>Success</h1><p>Your email was sent.</p>');
                    });
                }
        );
    });
});
Tsundoku
fuente
FYI: se fusionó de stackoverflow.com/questions/750358/…
Shog9
5

La mayoría de las soluciones que he visto esperan que diseñemos una superposición de carga, la mantengamos oculta y luego la ocultemos cuando sea necesario, o que muestremos un gif o una imagen, etc.

Quería desarrollar un complemento robusto, donde con una simple llamada jQuery puedo mostrar la pantalla de carga y derribarla cuando se complete la tarea.

Debajo está el código. Depende de Font awesome y jQuery:

/**
 * Raj: Used basic sources from here: http://jsfiddle.net/eys3d/741/
 **/


(function($){
    // Retain count concept: http://stackoverflow.com/a/2420247/260665
    // Callers should make sure that for every invocation of loadingSpinner method there has to be an equivalent invocation of removeLoadingSpinner
    var retainCount = 0;

    // http://stackoverflow.com/a/13992290/260665 difference between $.fn.extend and $.extend
    $.extend({
        loadingSpinner: function() {
            // add the overlay with loading image to the page
            var over = '<div id="custom-loading-overlay">' +
                '<i id="custom-loading" class="fa fa-spinner fa-spin fa-3x fa-fw" style="font-size:48px; color: #470A68;"></i>'+
                '</div>';
            if (0===retainCount) {
                $(over).appendTo('body');
            }
            retainCount++;
        },
        removeLoadingSpinner: function() {
            retainCount--;
            if (retainCount<=0) {
                $('#custom-loading-overlay').remove();
                retainCount = 0;
            }
        }
    });
}(jQuery)); 

Simplemente coloque lo anterior en un archivo js e inclúyalo durante todo el proyecto.

Además de CSS:

#custom-loading-overlay {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    right: 0;
    background: #000;
    opacity: 0.8;
    filter: alpha(opacity=80);
}
#custom-loading {
    width: 50px;
    height: 57px;
    position: absolute;
    top: 50%;
    left: 50%;
    margin: -28px 0 0 -25px;
}

Invocación:

$.loadingSpinner();
$.removeLoadingSpinner();
Raj Pawan Gumdal
fuente
4

Tenga en cuenta que cuando use ASP.Net MVC, con using (Ajax.BeginForm(..., la configuración de ajaxStartno funcionará.

Use AjaxOptionspara superar este problema:

(Ajax.BeginForm("ActionName", new AjaxOptions { OnBegin = "uiOfProccessingAjaxAction", OnComplete = "uiOfProccessingAjaxActionComplete" }))
Rami Weiss
fuente
FYI: se fusionó de stackoverflow.com/questions/750358/…
Shog9
2

Según https://www.w3schools.com/howto/howto_css_loader.asp , este es un proceso de 2 pasos sin JS:

1.Agregue este HTML donde desee el spinner: <div class="loader"></div>

2. Agregue este CSS para hacer el spinner real:

.loader {
    border: 16px solid #f3f3f3; /* Light grey */
    border-top: 16px solid #3498db; /* Blue */
    border-radius: 50%;
    width: 120px;
    height: 120px;
    animation: spin 2s linear infinite;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}
hamx0r
fuente
Dado que el OP está utilizando jQuery, pueden llamar $("#loader").toggle();antes de realizar la solicitud de ejecución prolongada para iniciar la animación y realizar otra llamada en la función de devolución de llamada de la solicitud para ocultarla.
Dmitri Chubarov
2

Yo uso CSS3 para animación

/************ CSS3 *************/
.icon-spin {
  font-size: 1.5em;
  display: inline-block;
  animation: spin1 2s infinite linear;
}

@keyframes spin1{
    0%{transform:rotate(0deg)}
    100%{transform:rotate(359deg)}
}

/************** CSS3 cross-platform ******************/

.icon-spin-cross-platform {
  font-size: 1.5em;
  display: inline-block;
  -moz-animation: spin 2s infinite linear;
  -o-animation: spin 2s infinite linear;
  -webkit-animation: spin 2s infinite linear;
  animation: spin2 2s infinite linear;
}

@keyframes spin2{
    0%{transform:rotate(0deg)}
    100%{transform:rotate(359deg)}
}
@-moz-keyframes spin2{
    0%{-moz-transform:rotate(0deg)}
    100%{-moz-transform:rotate(359deg)}
}
@-webkit-keyframes spin2{
    0%{-webkit-transform:rotate(0deg)}
    100%{-webkit-transform:rotate(359deg)}
}
@-o-keyframes spin2{
    0%{-o-transform:rotate(0deg)}
    100%{-o-transform:rotate(359deg)}
}
@-ms-keyframes spin2{
    0%{-ms-transform:rotate(0deg)}
    100%{-ms-transform:rotate(359deg)}
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>


<div class="row">
  <div class="col-md-6">
    Default CSS3
    <span class="glyphicon glyphicon-repeat icon-spin"></span>
  </div>
  <div class="col-md-6">
    Cross-Platform CSS3
    <span class="glyphicon glyphicon-repeat icon-spin-cross-platform"></span>
  </div>
</div>

Camille
fuente