Comment puis-je créer une animation «Veuillez patienter, charger…» à l'aide de jQuery?

585

Je voudrais placer une animation de cercle de rotation "veuillez patienter, chargement" sur mon site. Comment dois-je accomplir cela en utilisant jQuery?

thedp
la source

Réponses:

1211

Vous pouvez le faire de différentes manières. Cela peut être subtil comme un petit statut sur la page disant "Chargement ...", ou aussi fort qu'un élément entier grisant la page pendant le chargement des nouvelles données. L'approche que je prends ci-dessous vous montrera comment accomplir les deux méthodes.

La mise en place

Commençons par nous faire une belle animation de "chargement" de http://ajaxload.info que j'utiliseraientrez la description de l'image ici

Créons un élément que nous pouvons afficher / masquer chaque fois que nous faisons une demande ajax:

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

Le CSS

Donnons-lui ensuite un peu de flair:

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

Et enfin, le jQuery

D'accord, sur la jQuery. Cette partie suivante est en fait très simple:

$body = $("body");

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

C'est ça! Nous attachons certains événements à l'élément body chaque fois que les événements ajaxStartor ajaxStopsont déclenchés. Lorsqu'un événement ajax démarre, nous ajoutons la classe "loading" au corps. et lorsque les événements sont terminés, nous supprimons la classe "loading" du corps.

Voyez-le en action: http://jsfiddle.net/VpDUG/4952/

Sampson
la source
8
C'est la solution la plus approfondie, mais je vous recommande d'utiliser un plugin de centrage qui centre le préchargeur autour d'un élément de page ( c'est-à-dire le corps, #élément ou .élément )
Corey Ballou
2
Ce serait une belle addition, cballou. J'essayais simplement de minimiser l'information - mais comme vous le faites remarquer, elle peut certainement être améliorée.
Sampson
9
J'ai dû utiliser .bind () au lieu de .on () car nous utilisons jQuery 1.5.1!
renegadeMind
39
Je recommanderais d'utiliser le plugin qui se connecte aux plugins pour s'assurer qu'ils sont tous connectés.
contactmatt
15
Remarque: Depuis jQuery 1.8, la méthode .ajaxStop()et .ajaxStart()ne doit être attachée qu'au document. docs
balexandre
215

En ce qui concerne l'image de chargement réelle, consultez ce site pour un tas d'options.

En ce qui concerne l'affichage d'un DIV avec cette image lorsqu'une demande commence, vous avez plusieurs choix:

A) Affichez et masquez manuellement l'image:

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

B) Utilisez ajaxStart et ajaxComplete :

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

En utilisant cela, l'élément sera affiché / masqué pour toute demande. Peut être bon ou mauvais, selon le besoin.

C) Utilisez des rappels individuels pour une demande particulière:

$('#form').submit(function() {
    $.ajax({
        url: '/whatever.php',
        beforeSend: function() { $('#wait').show(); },
        complete: function() { $('#wait').hide(); }
    });
    return false;
});
Paolo Bergantino
la source
4
Quelque chose à noter: si vous ne pouvez pas modifier le HTML pour ajouter l'élément de chargement img, vous pouvez le faire comme image de fond sur le bouton en utilisant CSS, par exemple input.loading-gif {background: url ('images / loading.gif') ;} puis appliquez la classe avec jQuery, par exemple $ ('# mybutton'). addClass ('loading-gif'); Le seul problème est que cela ne demandera le gif que lorsque le bouton Soumettre est cliqué, ce qui est normalement trop tard, vous devez donc le mettre en cache, ce qui est facile avec jQuery, par exemple (new Image ()). Src = "images /loading.gif ";
jackocnr
4
Ce site a une plus grande et à mon avis une meilleure sélection de chargeurs avec plus d'options de personnalisation preloaders.net
rorypicko
FYI: fusionné de stackoverflow.com/questions/750358/…
Shog9
Belle solution, mais quand j'appelle show () après hide () ça ne marche pas . J'ai trouvé une solution qui est de basculer show () et hide () pour basculer (). En espérant que cela puisse aider quelqu'un à avoir le même problème que le mien. De plus, j'ai essayé la solution C) et j'ai fondé beforeSend ne fonctionnant pas en async. J'ai donc suggéré d'appeler show () au-dessus de $ .ajax pour fonctionner correctement.
劉鎮 瑲
Merci beaucoup @Paolo. Personnellement, j'ai aimé votre réponse que celle acceptée par la plupart des utilisateurs. Par conséquent, +1 à vous de mon côté.
Ashok kumar
113

Parallèlement à ce que Jonathan et Samir ont suggéré (les deux excellentes réponses btw!), JQuery a des événements intégrés qu'il déclenchera pour vous lors d'une demande ajax.

Il y a l' ajaxStartévénement

Afficher un message de chargement chaque fois qu'une demande AJAX démarre (et qu'aucune n'est déjà active).

... et c'est frère, l' ajaxStopévénement

Attachez une fonction à exécuter à la fin de toutes les requêtes AJAX. Il s'agit d'un événement Ajax.

Ensemble, ils constituent un excellent moyen d'afficher un message de progression lorsqu'une activité ajax se produit n'importe où sur la page.

HTML:

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

Scénario:

$(document).ajaxStart(function(){
    $('#loading').show();
 }).ajaxStop(function(){
    $('#loading').hide();
 });
Dan F
la source
Ceci est obsolète, en date du 1.8.0, .ajaxStartne peut être attaché qu'au document, c'est-à-dire. $(document).ajaxStart(function(){}).
Jonno_FTW
2
@Jonno_FTW corrigé. Ta. Anciennes questions et réponses qui ont été remplacées par les modifications de Jonathan Sampson à sa question, mais bon de le garder à jour de toute façon
Dan F
3
La réponse de Jonathan était très en profondeur, mais c'était pour moi la meilleure pour sa simplicité.
Ojonugwa Jude Ochalifu
19

Vous pouvez saisir un GIF animé d'un cercle tournant à partir d' Ajaxload - collez-le quelque part dans la hiérarchie des fichiers de votre site Web. Il vous suffit ensuite d'ajouter un élément HTML avec le code correct et de le supprimer lorsque vous avez terminé. C'est assez simple:

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

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

Il vous suffit alors d'utiliser ces méthodes dans votre appel 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();

Cela a quelques mises en garde: tout d'abord, si vous avez deux ou plusieurs endroits où l'image de chargement peut être affichée, vous devrez garder une trace du nombre d'appels en cours à la fois d'une manière ou d'une autre, et ne masquer que lorsqu'ils sont terminé. Cela peut être fait à l'aide d'un simple compteur, qui devrait fonctionner dans presque tous les cas.

Deuxièmement, cela ne masquera l'image de chargement que lors d'un appel AJAX réussi. Pour gérer les états d'erreur, vous devrez examiner $.ajaxce qui est plus complexe que $.load, $.getetc., mais beaucoup plus flexible également.

Samir Talwar
la source
2
Merci pour la réponse. Mais dites-moi, pourquoi dois-je utiliser AJAX? Je ne peux pas simplement retrouver tout cela dans la page elle-même?
thedp
Que voulez-vous exactement suivre? À moins que vous ne demandiez des informations après le chargement de la page (et AJAX est à peu près le seul moyen de le faire sans utiliser de plugin), pourquoi auriez-vous besoin d'une image de "chargement"?
Samir Talwar
Samir Talwar: Une application JavaScript lourde en fait. Merci, j'ai l'idée.
thedp
Compréhensible. Dans ce cas, appelez juste showLoadingImageavant de commencer et hideLoadingImageaprès avoir terminé. Devrait être assez simple. Vous devrez peut-être coller une sorte d' setTimeoutappel pour vous assurer que le navigateur restitue bien la nouvelle <img>balise - j'ai vu quelques cas où cela ne dérange pas jusqu'à ce que JavaScript soit terminé.
Samir Talwar,
16

L'excellente solution de Jonathon se casse dans IE8 (l'animation ne s'affiche pas du tout). Pour résoudre ce problème, changez le CSS en:

.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
la source
2
Modifié car les multiples lignes «background-» ne fonctionnaient pas, mais la seule instruction background fonctionne correctement.
Maurice Flanagan
7

jQuery fournit des hooks d'événements pour le début et la fin des requêtes AJAX. Vous pouvez vous y connecter pour montrer votre chargeur.

Par exemple, créez le div suivant:

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

Réglez-le display: nonedans vos feuilles de style. Vous pouvez le coiffer comme vous le souhaitez. Vous pouvez générer une belle image de chargement sur Ajaxload.info , si vous le souhaitez.

Ensuite, vous pouvez utiliser quelque chose comme le suivant pour le faire s'afficher automatiquement lors de l'envoi de demandes Ajax:

$(document).ready(function () {

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

});

Ajoutez simplement ce bloc Javascript à la fin de votre page avant de fermer votre balise body ou où bon vous semble.

Maintenant, chaque fois que vous envoyez des demandes Ajax, le #spinnerdiv sera affiché. Une fois la demande terminée, elle sera à nouveau masquée.

Veeti
la source
Quelqu'un peut-il expliquer ce que AJAX a à voir avec cela? Je ne peux pas simplement gérer tout cela dans la page sans accéder au serveur avec AJAX ... Ou est-ce que je manque quelque chose ici? Merci.
thedp
4
Ah - si j'ai bien compris, vous vouliez qu'une image de chargement soit affichée chaque fois que vous faisiez des demandes AJAX. Si vous souhaitez simplement afficher une animation "veuillez patienter, chargement ..." jusqu'à ce que la page soit entièrement chargée, vous pouvez avoir une div de chargement dans la page, puis la masquer dans votre bloc $ (document) .ready.
Veeti
7

Si vous utilisez Turbolinks With Rails, voici ma solution:

C'est le CoffeeScript

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

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

Ceci est le CSS SASS basé sur la première excellente réponse 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
la source
6

Comme l'a dit Mark H, le blockUI est le chemin.

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 .: J'ai reçu le ajax-loader.gif sur http://www.ajaxload.info/

bpedroso
la source
FYI: fusionné de stackoverflow.com/questions/750358/…
Shog9
6

Avec tout le respect que je dois aux autres articles, vous avez ici une solution très simple, utilisant CSS3 et jQuery, sans utiliser d'autres ressources ni fichiers externes.

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

Cela ferait disparaître les boutons, puis une animation de "chargement" apparaîtrait à leur place et afficherait finalement juste un message de réussite.

$(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
la source
FYI: fusionné de stackoverflow.com/questions/750358/…
Shog9
5

La plupart des solutions que j'ai vues attendent de nous que nous concevions une superposition de chargement, la gardions cachée et ensuite la révélions si nécessaire, ou, montrons un gif ou une image etc.

Je voulais développer un plugin robuste, où avec un simple appel jQuery, je peux afficher l'écran de chargement et le démonter lorsque la tâche est terminée.

Voici le code. Cela dépend de Font awesome et 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)); 

Il suffit de mettre ce qui précède dans un fichier js et de l'inclure tout au long du projet.

Ajout 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;
}

Invocation:

$.loadingSpinner();
$.removeLoadingSpinner();
Raj Pawan Gumdal
la source
4

Notez que lorsque vous utilisez ASP.Net MVC, avec using (Ajax.BeginForm(..., la définition de ajaxStartne fonctionnera pas.

Utilisez le AjaxOptionspour surmonter ce problème:

(Ajax.BeginForm("ActionName", new AjaxOptions { OnBegin = "uiOfProccessingAjaxAction", OnComplete = "uiOfProccessingAjaxActionComplete" }))
Rami Weiss
la source
FYI: fusionné de stackoverflow.com/questions/750358/…
Shog9
2

Par https://www.w3schools.com/howto/howto_css_loader.asp , il s'agit d'un processus en 2 étapes sans JS:

1.Ajoutez ce HTML où vous voulez que le spinner: <div class="loader"></div>

2.Ajoutez ce CSS pour créer le véritable spinner:

.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
la source
Étant donné que l'OP utilise jQuery, ils peuvent appeler $("#loader").toggle();avant d'effectuer la demande de longue durée pour démarrer l'animation et effectuer un autre appel dans la fonction de rappel de la demande pour la masquer.
Dmitri Chubarov
2

J'utilise CSS3 pour l'animation

/************ 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
la source