¿Cómo agregar un ícono giratorio al botón cuando está en el estado Cargando?


190

Los botones de Twitter Bootstrap tienen un buen Loading...estado disponible.

Lo que pasa es que solo muestra un mensaje como Loading...pasado a través del data-loading-textatributo como este:

<button type="button" class="btn btn-primary start" id="btnStartUploads"
        data-loading-text="@Localization.Uploading">
    <i class="icon-upload icon-large"></i>
    <span>@Localization.StartUpload</span>
</button>

Al mirar Font Awesome, ves que ahora hay un ícono giratorio animado .

Intenté integrar ese ícono giratorio al disparar una Uploadoperación como esta:

$("#btnStartUploads").button('loading');
$("#btnStartUploads i").removeAttr('class');
$("#btnStartUploads i").addClass('icon-spinner icon-spin icon-large');

pero esto no tuvo ningún efecto, es decir, solo veo el Uploading...texto en el botón.

¿Es posible agregar un icono cuando el botón está en el estado Cargando? Parece que Bootstrap de alguna manera simplemente elimina el ícono <i class="icon-upload icon-large"></i>dentro del botón mientras está en el estado Cargando.


Aquí hay una demostración simple que muestra el comportamiento que describo anteriormente. Como ve cuando entra en el estado Cargando, el icono simplemente desaparece. Reaparece justo después del intervalo de tiempo.


1
Puede consultar mi solución para animar la apariencia de la ruleta: stackoverflow.com/questions/15982233/…
Andrew Dryga

Recomiendo utilizar este enfoque stackoverflow.com/a/15988830/437690
limitium

Respuestas:


101

Si observa la fuente bootstrap-button.js , verá que el complemento bootstrap reemplaza el html interno de los botones con lo que esté en el texto de carga de datos al llamar $(myElem).button('loading').

Para su caso, creo que debería poder hacer esto:

<button type="button"
        class="btn btn-primary start"
        id="btnStartUploads"
        data-loading-text="<i class='icon-spinner icon-spin icon-large'></i> @Localization.Uploading">
    <i class="icon-upload icon-large"></i>
    <span>@Localization.StartUpload</span>
</button>

1
Funciona muy bien gurch101! Olvidé que se puede mezclar HTMLcon texto en una propiedad de etiqueta. :-)
Leniel Maccaferri

11
Fiddle no funciona para Safari 6.0.5 (7536.30.1), Chrome 31.0.1604.0 canary en Mac OS X.
Burak Erdem

16
Reparado: jsfiddle.net/6U5q2/270 Tenga en cuenta que esto es para v2.3.2. No sé si funciona para 3.x
Eric Freese

13
data-loading-textestá en desuso desde v3.3.5 y se eliminará en v4.
Jonathan

2
@ Jonathan Si está en desuso en v3.3.5, ¿cuál es el reemplazo para eso en v3.3.5 y v4?
PaladiN

323

Solución simple para Bootstrap 3 usando animaciones CSS3.

Pon lo siguiente en tu CSS:

.glyphicon.spinning {
    animation: spin 1s infinite linear;
    -webkit-animation: spin2 1s infinite linear;
}

@keyframes spin {
    from { transform: scale(1) rotate(0deg); }
    to { transform: scale(1) rotate(360deg); }
}

@-webkit-keyframes spin2 {
    from { -webkit-transform: rotate(0deg); }
    to { -webkit-transform: rotate(360deg); }
}

Luego solo agrega la spinningclase a un glyphiconmomento de carga para obtener tu ícono giratorio:

<button class="btn btn-lg btn-warning">
    <span class="glyphicon glyphicon-refresh spinning"></span> Loading...    
</button>

Basado en http://www.bootply.com/128062#

  • Nota: IE9 y versiones posteriores no admiten animaciones CSS3.

44
¿No debería ser animationy no -animation?
Andrey Mikhaylov - lolmaus

3
Excelente solucion. Tengo problemas con esta animación en Safari en el escritorio y en el iPad. Muestra el ícono pero no lo anima. ¿Alguna vez has experimentado algo así?
JayhawksFan93

@ JayhawksFan93 sí, recientemente noté lo mismo en IE. Lo investigaremos pronto
Flion

2
la respuesta se actualizó en animationlugar de -animation. Con ese cambio bien en FF e IE para mí. Sin embargo, la animación de Firefox no se ve muy suave.
Flion

1
+1. Encontrado una similar aquí .... registro de entradas para obtener ...
Fr0zenFyr


13

Para que la solución de @flion se vea realmente genial, puede ajustar el punto central de ese icono para que no se tambalee hacia arriba y hacia abajo. Esto se ve bien para mí en un tamaño de fuente pequeño:

.glyphicon-refresh.spinning {
  transform-origin: 48% 50%;
}

1
.glyphicon-refresh.spinning { transform-origin: 50% 58%; }funcionó para mí
oluckyman

zumbido, { transform-origin: 50% 49%; }resolver en mi caso donde estoy usando en su coglugar.
Vitor Canova

También noto el bamboleo, pero ¿cuál es la razón para cambiar estos números? ¿Cómo debo sintonizarlos?
elachell

2

Aquí está mi solución para Bootstrap 4:

<button id="search" class="btn btn-primary" 
data-loading-text="<i class='fa fa-spinner fa-spin fa-fw' aria-hidden='true'></i>Searching">
  Search
</button>

var setLoading = function () {
  var search = $('#search');
  if (!search.data('normal-text')) {
    search.data('normal-text', search.html());
  }
  search.html(search.data('loading-text'));
};

var clearLoading = function () {
  var search = $('#search');
  search.html(search.data('normal-text'));
};

setInterval(() => {
  setLoading();
  setTimeout(() => {
    clearLoading();
  }, 1000);
}, 2000);

Compruébalo en JSFiddle


2

Estos son míos, basados ​​en animaciones SVG y CSS puras. No preste atención al código JS en el fragmento a continuación, es solo para fines de demostración. Siéntase libre de hacer que sus personalizados se basen en los míos, es muy fácil.

var svg = d3.select("svg"),
    columnsCount = 3;

['basic', 'basic2', 'basic3', 'basic4', 'loading', 'loading2', 'spin', 'chrome', 'chrome2', 'flower', 'flower2', 'backstreet_boys'].forEach(function(animation, i){
  var x = (i%columnsCount+1) * 200-100,
      y = 20 + (Math.floor(i/columnsCount) * 200);
  
  
  svg.append("text")
    .attr('text-anchor', 'middle')
    .attr("x", x)
    .attr("y", y)
    .text((i+1)+". "+animation);
  
  svg.append("circle")
    .attr("class", animation)
    .attr("cx",  x)
    .attr("cy",  y+40)
    .attr("r",  16)
});
circle {
  fill: none;
  stroke: #bbb;
  stroke-width: 4
}

.basic {
  animation: basic 0.5s linear infinite;
  stroke-dasharray: 20 80;
}

@keyframes basic {
  0%    {stroke-dashoffset: 100;}
  100%  {stroke-dashoffset: 0;}
}

.basic2 {
  animation: basic2 0.5s linear infinite;
  stroke-dasharray: 80 20;
}

@keyframes basic2 {
  0%    {stroke-dashoffset: 100;}
  100%  {stroke-dashoffset: 0;}
}

.basic3 {
  animation: basic3 0.5s linear infinite;
  stroke-dasharray: 20 30;
}

@keyframes basic3 {
  0%    {stroke-dashoffset: 100;}
  100%  {stroke-dashoffset: 0;}
}

.basic4 {
  animation: basic4 0.5s linear infinite;
  stroke-dasharray: 10 23.3;
}

@keyframes basic4 {
  0%    {stroke-dashoffset: 100;}
  100%  {stroke-dashoffset: 0;}
}

.loading {
  animation: loading 1s linear infinite;
  stroke-dashoffset: 25;
}

@keyframes loading {
  0%    {stroke-dashoffset: 0;    stroke-dasharray: 50 0; }
  50%   {stroke-dashoffset: -100; stroke-dasharray: 0 50;}
  100%  { stroke-dashoffset: -200;stroke-dasharray: 50 0;}
}

.loading2 {
  animation: loading2 1s linear infinite;
}

@keyframes loading2 {
  0% {stroke-dasharray: 5 28.3;   stroke-dashoffset: 75;}
  50% {stroke-dasharray: 45 5;    stroke-dashoffset: -50;}
  100% {stroke-dasharray: 5 28.3; stroke-dashoffset: -125; }
}

.spin {
  animation: spin 1s linear infinite;
  stroke-dashoffset: 25;
}

@keyframes spin {
  0%    {stroke-dashoffset: 0;    stroke-dasharray: 33.3 0; }
  50%   {stroke-dashoffset: -100; stroke-dasharray: 0 33.3;}
  100%  { stroke-dashoffset: -200;stroke-dasharray: 33.3 0;}
}

.chrome {
  animation: chrome 2s linear infinite;
}

@keyframes chrome {
  0%    {stroke-dasharray: 0 100; stroke-dashoffset: 25;}
  25%   {stroke-dasharray: 75 25; stroke-dashoffset: 0;}
  50%   {stroke-dasharray: 0 100;  stroke-dashoffset: -125;}
  75%    {stroke-dasharray: 75 25; stroke-dashoffset: -150;}
  100%   {stroke-dasharray: 0 100; stroke-dashoffset: -275;}
}

.chrome2 {
  animation: chrome2 1s linear infinite;
}

@keyframes chrome2 {
  0%    {stroke-dasharray: 0 100; stroke-dashoffset: 25;}
  25%   {stroke-dasharray: 50 50; stroke-dashoffset: 0;}
  50%   {stroke-dasharray: 0 100;  stroke-dashoffset: -50;}
  75%   {stroke-dasharray: 50 50;  stroke-dashoffset: -125;}
  100%  {stroke-dasharray: 0 100;  stroke-dashoffset: -175;}
}

.flower {
  animation: flower 1s linear infinite;
}

@keyframes flower {
  0%    {stroke-dasharray: 0  20; stroke-dashoffset: 25;}
  50%   {stroke-dasharray: 20 0;  stroke-dashoffset: -50;}
  100%  {stroke-dasharray: 0 20;  stroke-dashoffset: -125;}
}

.flower2 {
  animation: flower2 1s linear infinite;
}

@keyframes flower2 {
  0%    {stroke-dasharray: 5 20;  stroke-dashoffset: 25;}
  50%   {stroke-dasharray: 20 5;  stroke-dashoffset: -50;}
  100%  {stroke-dasharray: 5 20;  stroke-dashoffset: -125;}
}

.backstreet_boys {
  animation: backstreet_boys 3s linear infinite;
}

@keyframes backstreet_boys {
  0%    {stroke-dasharray: 5 28.3;  stroke-dashoffset: -225;}
  15%    {stroke-dasharray: 5 28.3;  stroke-dashoffset: -300;}
  30%   {stroke-dasharray: 5 20;  stroke-dashoffset: -300;}
  45%    {stroke-dasharray: 5 20;  stroke-dashoffset: -375;}
  60%   {stroke-dasharray: 5 15;  stroke-dashoffset: -375;}
  75%    {stroke-dasharray: 5 15;  stroke-dashoffset: -450;}
  90%   {stroke-dasharray: 5 15;  stroke-dashoffset: -525;}
  100%   {stroke-dasharray: 5 28.3;  stroke-dashoffset: -925;}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<svg width="600px" height="700px"></svg>

También disponible en CodePen: https://codepen.io/anon/pen/PeRazr


1

Aquí hay una solución completa de CSS inspirada en Bulma. Solo agrega

    .button {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      position: relative;
      min-width: 200px;
      max-width: 100%;
      min-height: 40px;
      text-align: center;
      cursor: pointer;
    }

    @-webkit-keyframes spinAround {
      from {
        -webkit-transform: rotate(0deg);
        transform: rotate(0deg);
      }
      to {
        -webkit-transform: rotate(359deg);
        transform: rotate(359deg);
      }
    }
    @keyframes spinAround {
      from {
        -webkit-transform: rotate(0deg);
        transform: rotate(0deg);
      }
      to {
        -webkit-transform: rotate(359deg);
        transform: rotate(359deg);
      }
    }

    .button.is-loading {
      text-indent: -9999px;
      box-shadow: none;
      font-size: 1rem;
      height: 2.25em;
      line-height: 1.5;
      vertical-align: top;
      padding-bottom: calc(0.375em - 1px);
      padding-left: 0.75em;
      padding-right: 0.75em;
      padding-top: calc(0.375em - 1px);
      white-space: nowrap;
    }

    .button.is-loading::after  {
      -webkit-animation: spinAround 500ms infinite linear;
      animation: spinAround 500ms infinite linear;
      border: 2px solid #dbdbdb;
      border-radius: 290486px;
      border-right-color: transparent;
      border-top-color: transparent;
      content: "";
      display: block;
      height: 1em;
      position: relative;
      width: 1em;
    }
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.