Respuestas:
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.
Comencemos por obtener una buena animación de "carga" de http://ajaxload.info que usaré
Creemos un elemento que podamos mostrar / ocultar cada vez que hagamos una solicitud ajax:
<div class="modal"><!-- Place at bottom of page --></div>
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;
}
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 ajaxStart
o 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/
.ajaxStop()
y .ajaxStart()
solo debe adjuntarse al documento. docs
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;
});
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 ajaxStart
evento
Muestra un mensaje de carga cada vez que se inicia una solicitud AJAX (y ninguna está activa).
... y es hermano, el ajaxStop
evento
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();
});
.ajaxStart
solo se puede adjuntar al documento, es decir. $(document).ajaxStart(function(){}).
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
, $.get
y similares, pero también mucho más flexible.
showLoadingImage
antes de comenzar y hideLoadingImage
después de terminar. Debería ser bastante simple. Sin embargo, es posible que deba pegar algún tipo de setTimeout
llamada 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.
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)};
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: none
en 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, #spinner
se mostrará el div. Cuando se complete la solicitud, se ocultará nuevamente.
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;
}
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/
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" />
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>');
});
}
);
});
});
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();
Tenga en cuenta que cuando use ASP.Net MVC, con using (Ajax.BeginForm(...
, la configuración de ajaxStart
no funcionará.
Use AjaxOptions
para superar este problema:
(Ajax.BeginForm("ActionName", new AjaxOptions { OnBegin = "uiOfProccessingAjaxAction", OnComplete = "uiOfProccessingAjaxActionComplete" }))
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); }
}
$("#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.
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>