Comment ajouter une icône de spinner au bouton lorsqu'il est en état de chargement?

191

Les boutons de Twitter Bootstrap ont un bon Loading...état disponible.

Le fait est qu'il montre juste un message comme Loading...passé par l' data-loading-textattribut comme ceci:

<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>

En regardant Font Awesome, vous voyez qu'il y a maintenant une icône de spinner animée .

J'ai essayé d'intégrer cette icône de spinner lors du lancement d'une Uploadopération comme celle-ci:

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

mais cela n'a eu aucun effet, c'est-à-dire que je vois juste le Uploading...texte sur le bouton.

Est-il possible d'ajouter une icône lorsque le bouton est à l'état Chargement? On dirait que Bootstrap supprime simplement l'icône <i class="icon-upload icon-large"></i>à l'intérieur du bouton lorsqu'il est à l'état de chargement.


Voici une démo simple qui montre le comportement que je décris ci-dessus. Comme vous le voyez quand il entre dans l'état de chargement, l'icône disparaît simplement. Il réapparaît juste après l'intervalle de temps.

Leniel Maccaferri
la source
1
Vous pouvez consulter ma solution pour animer l'apparence du spinner: stackoverflow.com/questions/15982233/…
Andrew Dryga
Je recommande d'utiliser cette approche stackoverflow.com/a/15988830/437690
limitium

Réponses:

101

Si vous regardez la source bootstrap-button.js , vous verrez que le plugin bootstrap remplace les boutons html internes par tout ce qui se trouve dans le data-loading-text lors de l'appel $(myElem).button('loading').

Pour votre cas, je pense que vous devriez simplement pouvoir le faire:

<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>
gurch101
la source
1
Fonctionne très bien gurch101! J'oublie qu'on peut mélanger HTMLavec du texte dans une propriété de balise. :-)
Leniel Maccaferri
11
Fiddle ne fonctionne pas pour Safari 6.0.5 (7536.30.1), Chrome 31.0.1604.0 canary sur Mac OS X.
Burak Erdem
16
Correction: jsfiddle.net/6U5q2/270 Notez que c'est pour la v2.3.2. Je ne sais pas si cela fonctionne pour 3.x
Eric Freese
13
data-loading-textest obsolète depuis la v3.3.5 et sera supprimée dans la v4.
Jonathan
2
@Jonathan Si elle est obsolète dans la v3.3.5, quel est le remplacement pour cela à la fois après la v3.3.5 et la v4?
PaladiN
325

Solution simple pour Bootstrap 3 utilisant des animations CSS3.

Mettez ce qui suit dans votre 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); }
}

Ensuite, ajoutez simplement la spinningclasse à un glyphiconmoment de chargement pour obtenir votre icône en rotation:

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

Basé sur http://www.bootply.com/128062#

  • Remarque: IE9 et les versions antérieures ne prennent pas en charge les animations CSS3.
Flion
la source
4
Ne devrait-il pas l'être animationet non -animation?
Andrey Mikhaylov - lolmaus
3
Excellente solution. J'ai des problèmes avec cette animation dans Safari sur le bureau et sur l'iPad. Il montre l'icône mais ne l'anime pas. Avez-vous déjà vécu quelque chose comme ça?
JayhawksFan93
@ JayhawksFan93 oui j'ai récemment remarqué la même chose dans IE. Je l'examinerai bientôt
Flion
2
la réponse a été mise à jour au animationlieu de -animation. Avec ce changement bien dans FF et IE pour moi. L'animation de Firefox n'a cependant pas l'air très fluide.
Flion
1
+1. Trouvé un semblable ici .... affichage pour l' enregistrement ...
Fr0zenFyr
66

Il existe maintenant un plugin à part entière pour cela:

http://msurguy.github.io/ladda-bootstrap/

Raveren
la source
1
Salut @Eru Penkman. Quelle est la différence entre le vôtre et l'original?
Ivan Wang
Hey Ivan, trie mais je n'ai jamais mis à jour ma copie de ladda! C'est juste l'original, j'ai supprimé mon commentaire précédent. Désolé pour ça!
roo2
13

Pour que la solution de @flion soit vraiment géniale, vous pouvez ajuster le point central de cette icône afin qu'elle ne vacille pas de haut en bas. Cela me semble parfait avec une petite taille de police:

.glyphicon-refresh.spinning {
  transform-origin: 48% 50%;
}
jake
la source
1
.glyphicon-refresh.spinning { transform-origin: 50% 58%; }travaillé pour moi
oluckyman
hum, { transform-origin: 50% 49%; }résolvez dans mon cas où j'utilise à la cogplace.
Vitor Canova
Je remarque également l'oscillation, mais quelle est la raison pour laquelle changer ces chiffres? Comment dois-je les régler?
elachell le
2

Voici ma solution pour 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);

Découvrez-le sur JSFiddle

Mikemsq
la source
2

Ce sont les miens, basés sur des animations SVG et CSS pures. Ne faites pas attention au code JS dans l'extrait ci-dessous, c'est juste à des fins de démonstration. N'hésitez pas à en créer des personnalisés en vous basant sur le mien, c'est super facile.

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>

Également disponible sur CodePen: https://codepen.io/anon/pen/PeRazr

Damiano
la source
1

Voici une solution css à part entière inspirée de Bulma. Ajoutez simplement

    .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;
    }
Brendan Weinstein
la source
0

La seule chose que j'ai trouvée qui fonctionnait était un post ici: https://stackoverflow.com/a/44548729/9488229

Je l'ai amélioré, et maintenant il offre toutes ces fonctionnalités:

  • Désactivez le bouton après avoir cliqué
  • Afficher une icône de chargement animée à l'aide du bootstrap natif
  • Réactivez le bouton une fois le chargement de la page terminé
  • Le texte revient à l'original lorsque le chargement de la page est terminé

Javascript:

$(document).ready(function () {
    $('.btn').on('click', function() {
        var e=this;
        setTimeout(function() {
            e.innerHTML='<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Searching...';
            e.disabled=true;
        },0);
        return true;
    });
});
Colin
la source
Bienvenue dans Stack Overflow. Je ne vois pas où vous avez utilisé la solution utilisée par Andreas, et je ne vois pas dans le code fourni où le bouton est réactivé ou restauré.
Jason Aller
Vous avez raison, c'était une autre réponse, j'ai mis à jour le lien. Quant à savoir comment le bouton est réactivé, cela fonctionne. Je pense que cela a à voir avec le fait qu'il est désactivé dans une fonction setTimeout () que tout ce qui se passe à l'intérieur de cette fonction est annulé lorsque la page a fini de se charger. C'est une solution vraiment propre.
Colin le
Il se peut que la réactivation et la restauration de texte soient prises en charge par Bootstrap. Essayez d'exécuter ce code sans le JavaScript Bootstrap sur une page de test.
Jason Aller le