Como posso criar uma animação "Aguarde, carregando ..." usando o jQuery?

585

Gostaria de colocar uma animação de círculo giratório "aguarde, carregando" no meu site. Como devo fazer isso usando o jQuery?

thedp
fonte

Respostas:

1211

Você poderia fazer isso de várias maneiras diferentes. Pode ser um status sutil como pequeno na página dizendo "Carregando ..." ou tão alto quanto um elemento inteiro acinzentando a página enquanto os novos dados estão sendo carregados. A abordagem que estou adotando abaixo mostrará como realizar os dois métodos.

A Instalação

Vamos começar com uma boa animação de "carregamento" em http://ajaxload.info que eu usareiinsira a descrição da imagem aqui

Vamos criar um elemento que possamos mostrar / ocultar sempre que fizermos uma solicitação ajax:

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

O CSS

Em seguida, vamos dar um toque:

/* 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;
}

E, finalmente, o jQuery

Tudo bem, para o jQuery. Esta próxima parte é realmente muito simples:

$body = $("body");

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

É isso aí! Anexamos alguns eventos ao elemento body sempre que os eventos ajaxStartou ajaxStopsão disparados. Quando um evento ajax é iniciado, adicionamos a classe "loading" ao corpo. e quando os eventos são concluídos, removemos a classe "loading" do corpo.

Veja em ação: http://jsfiddle.net/VpDUG/4952/

Sampson
fonte
8
Este é o mais em solução profundidade embora eu recomendo que você use um plugin de centralização que se centra o preloader em torno de um elemento da página ( ou seja, corpo, #element, ou .element )
Corey Ballou
2
Seria uma boa adição, cballou. Eu estava apenas tentando manter as informações minimizadas - mas, como você ressalta, elas certamente podem ser melhoradas.
Sampson
9
Eu tive que usar .bind () em vez de .on () porque estamos usando o jQuery 1.5.1!
renegadeMind
38
Eu recomendo usar o plugin que plugins para os plugins para se certificar de que eles estão todos conectados.
contactmatt
15
Nota: A partir do jQuery 1.8, o método .ajaxStop()e .ajaxStart()deve ser anexado apenas ao documento. docs
balexandre
215

Quanto à imagem de carregamento real, consulte este site para várias opções.

Quanto a exibir um DIV com esta imagem quando uma solicitação é iniciada, você tem algumas opções:

A) Mostre e oculte manualmente a imagem:

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

B) Use ajaxStart e ajaxComplete :

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

Usando isso, o elemento mostrará / ocultará qualquer solicitação. Pode ser bom ou ruim, dependendo da necessidade.

C) Use retornos de chamada individuais para uma solicitação específica:

$('#form').submit(function() {
    $.ajax({
        url: '/whatever.php',
        beforeSend: function() { $('#wait').show(); },
        complete: function() { $('#wait').hide(); }
    });
    return false;
});
Paolo Bergantino
fonte
4
Algo a ser observado: se você não pode modificar o HTML para adicionar o elemento loading img, pode fazê-lo como uma imagem de plano de fundo no botão usando CSS, por exemplo, input.loading-gif {background: url ('images / loading.gif') ;} e aplique a classe com jQuery, por exemplo, $ ('# mybutton'). addClass ('loading-gif'); O único problema é que isso só solicitará o gif quando o botão enviar for clicado, o que normalmente é tarde demais, então você precisa pré-armazenar em cache, o que é fácil com o jQuery, por exemplo (nova imagem ()). Src = "images /loading.gif ";
23411 jackocnr
4
Este site tem uma seleção maior e, na minha opinião, mais agradável de carregadores com mais opções de personalização preloaders.net
rorypicko
FYI: fusão desde stackoverflow.com/questions/750358/...
Shog9
Solução agradável, mas quando chamo show () após hide () não está funcionando . Eu encontrei uma solução que é switch show () e hide () para alternar (). Espero que ajude alguém a ter o mesmo problema que o meu. Além disso, tentei a solução C) e fundei beforeSend não funcionando em assíncrono. Então, sugeri ligar para show () acima de $ .ajax para funcionar corretamente.
劉鎮瑲
Muito obrigado @Paolo. Pessoalmente, gostei da sua resposta do que a aceita pela maioria dos usuários. Portanto, +1 para você do meu lado.
Ashok kumar
113

Juntamente com o que Jonathan e Samir sugeriram (ambas excelentes respostas!), O jQuery criou alguns eventos que serão acionados para você ao fazer uma solicitação de ajax.

Tem o ajaxStartevento

Mostre uma mensagem de carregamento sempre que uma solicitação AJAX for iniciada (e nenhuma já estiver ativa).

... e é irmão, o ajaxStopevento

Anexe uma função a ser executada sempre que todas as solicitações AJAX terminarem. Este é um evento do Ajax.

Juntos, eles são uma ótima maneira de mostrar uma mensagem de progresso quando qualquer atividade do ajax está acontecendo em qualquer lugar da página.

HTML:

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

Roteiro:

$(document).ajaxStart(function(){
    $('#loading').show();
 }).ajaxStop(function(){
    $('#loading').hide();
 });
Dan F
fonte
Isso está desatualizado, a partir do 1.8.0, .ajaxStartsó pode ser anexado ao documento, ou seja. $(document).ajaxStart(function(){}).
Jonno_FTW
2
@Jonno_FTW corrigido. Ta. Velha pergunta e resposta que tem sido substituído pelo edições de Jonathan Sampson à sua pergunta, mas bom para mantê-lo até à data qualquer maneira
Dan F
3
A resposta de Jonathan foi muito inapta, mas isso para mim foi o melhor por sua simplicidade.
Ojonugwa Jude Ochalifu
19

Você pode pegar um GIF animado de um círculo giratório em Ajaxload - coloque-o em algum lugar da hierarquia de arquivos do site. Então você só precisa adicionar um elemento HTML com o código correto e removê-lo quando terminar. Isso é bastante simples:

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

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

Você só precisa usar estes métodos na sua chamada 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();

Isso tem algumas advertências: primeiro, se você tiver dois ou mais locais em que a imagem de carregamento pode ser exibida, precisará acompanhar quantas chamadas estão sendo executadas ao mesmo tempo e se esconder apenas quando estiverem tudo feito. Isso pode ser feito usando um contador simples, que deve funcionar em quase todos os casos.

Em segundo lugar, isso ocultará apenas a imagem de carregamento em uma chamada AJAX bem-sucedida. Para lidar com os estados de erro, você precisa olhar para $.ajax, que é mais complexo do que $.load, $.gete similares, mas muito mais flexível também.

Samir Talwar
fonte
2
Obrigado pela resposta. Mas me diga, por que preciso usar o AJAX? Não posso simplesmente rastrear tudo na própria página?
thedp 27/12/2009
O que exatamente você deseja acompanhar? A menos que você solicite informações após o carregamento da página (e o AJAX é praticamente a única maneira de fazer isso sem usar um plug-in), por que você precisaria de uma imagem de "carregamento"?
Samir Talwar
Samir Talwar: Um aplicativo JavaScript pesado, na verdade. Obrigado, entendi a ideia.
thedp
Compreensível. Nesse caso, basta ligar showLoadingImageantes de começar e hideLoadingImagedepois de terminar. Deve ser bastante simples. Você pode precisar fazer algum tipo de setTimeoutchamada para garantir que o navegador realmente renderize a nova <img>tag - eu já vi alguns casos em que isso não incomoda até o JavaScript terminar de executar.
Samir Talwar
16

A excelente solução de Jonathon é interrompida no IE8 (a animação não é exibida). Para corrigir isso, altere o CSS para:

.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
fonte
2
Editado porque as várias linhas 'background-' não funcionaram, mas a única instrução background funciona corretamente.
Maurice Flanagan
7

O jQuery fornece ganchos de eventos para quando as solicitações do AJAX começam e terminam. Você pode conectar-se a eles para mostrar seu carregador.

Por exemplo, crie a seguinte div:

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

Defina-o display: noneem suas folhas de estilo. Você pode modelá-lo da maneira que quiser. Você pode gerar uma boa imagem de carregamento no Ajaxload.info , se desejar.

Em seguida, você pode usar algo como o seguinte para fazer com que seja mostrado automaticamente ao enviar solicitações do Ajax:

$(document).ready(function () {

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

});

Basta adicionar este bloco Javascript ao final da sua página antes de fechar a etiqueta do corpo ou onde quiser.

Agora, sempre que você enviar solicitações Ajax, a #spinnerdiv será mostrada. Quando a solicitação for concluída, ela será ocultada novamente.

Veeti
fonte
Alguém pode explicar o que o AJAX tem a ver com isso? Não posso simplesmente gerenciar tudo isso na página sem acessar o servidor com AJAX ... Ou estou faltando alguma coisa aqui? Obrigado.
thedp 27/12/2009
4
Ah - como eu entendi, você queria que uma imagem de carregamento fosse mostrada sempre que estivesse solicitando AJAX. Se você simplesmente deseja que uma animação "por favor aguarde, carregando ..." seja mostrada até que a página esteja totalmente carregada, você pode ter uma div de carregamento na página e depois ocultá-la no seu bloco $ (documento) .ready.
Veeti 27/12/2009
7

Se você estiver usando o Turbolinks With Rails, esta é a minha solução:

Este é o CoffeeScript

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

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

Este é o CSS do SASS baseado na primeira excelente resposta 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
fonte
6

Como Mark H disse, o blockUI é o caminho.

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 .: peguei o ajax-loader.gif em http://www.ajaxload.info/

bpedroso
fonte
FYI: fusão desde stackoverflow.com/questions/750358/...
Shog9
6

Com todo o respeito a outras postagens, você tem aqui uma solução muito simples, usando CSS3 e jQuery, sem usar outros recursos nem arquivos externos.

$('#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
fonte
5

Isso faria os botões desaparecerem, uma animação de "carregamento" apareceria no lugar deles e, finalmente, apenas exibiria uma mensagem de sucesso.

$(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
fonte
FYI: fusão desde stackoverflow.com/questions/750358/...
Shog9
5

A maioria das soluções que eu vejo espera que projetemos uma sobreposição de carregamento, mantenha-a oculta e depois a reexiba quando necessário, ou mostre um gif ou imagem etc.

Eu queria desenvolver um plugin robusto, onde, com uma simples chamada jQuery, eu possa exibir a tela de carregamento e derrubá-la quando a tarefa estiver concluída.

Abaixo está o código. Depende da fonte awesome e 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)); 

Basta colocar o acima em um arquivo js e incluí-lo em todo o projeto.

Adição 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;
}

Invocação:

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

Observe que, ao usar o ASP.Net MVC, com using (Ajax.BeginForm(..., a configuração de ajaxStartnão funcionará.

Use o AjaxOptionspara superar esse problema:

(Ajax.BeginForm("ActionName", new AjaxOptions { OnBegin = "uiOfProccessingAjaxAction", OnComplete = "uiOfProccessingAjaxActionComplete" }))
Rami Weiss
fonte
FYI: fusão desde stackoverflow.com/questions/750358/...
Shog9
2

Por https://www.w3schools.com/howto/howto_css_loader.asp , este é um processo de duas etapas sem JS:

1. Adicione este HTML onde você deseja o botão giratório: <div class="loader"></div>

2. Adicione este CSS para fazer o girador 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
fonte
Como o OP está usando o jQuery, eles podem chamar $("#loader").toggle();antes de fazer a solicitação de longa execução para iniciar a animação e fazer outra chamada na função de retorno de chamada da solicitação para ocultá-la.
Dmitri Chubarov
2

Eu uso CSS3 para animação

/************ 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
fonte