2009-10-20 10 views
19

Dans de nombreux cas, je souhaite que l'animation soit exécutée de manière synchrone. Surtout quand je souhaite faire une série d'animations séquentielles.Animation synchrone JQuery

Existe-t-il un moyen facile de synchroniser un appel de fonction jQuery animate?

La seule façon dont j'ai pensé est de mettre un drapeau vrai lorsque l'animation est terminée et d'attendre ce drapeau.

Répondre

24

jQuery ne peut pas créer d'animations synchrones. N'oubliez pas que JavaScript s'exécute sur le thread de l'interface utilisateur du navigateur.

Si vous réalisez une animation synchrone, le navigateur se bloque jusqu'à la fin de l'animation.

Pourquoi avez-vous besoin de faire cela?

Vous devriez probablement utiliser le paramètre de rappel de jQuery et continuer votre code de méthode dans le rappel, comme ceci:

function doSomething() { 
    var thingy = whatever; 
    //Do things 
    $('something').animate({ width: 70 }, function() { 
     //jQuery will call this method after the animation finishes. 
     //You can continue your code here. 
     //You can even access variables from the outer function 
     thingy = thingy.fiddle; 
    }); 
} 

Ceci est appelé une fermeture.

+0

Je pense que vous pouvez échapper à thread d'interface utilisateur avec setTimeout, afin que je puisse vraiment utiliser l'animation non bloquante dans une fonction setTimeout d'avoir un sain d'esprit du code à la recherche d'animations séquentielles . –

+8

Vous avez tort. 'setTimeout' n'exécute pas le rappel sur un thread différent; il attend que le thread de l'interface utilisateur devienne libre puis appelle le rappel sur le thread de l'interface utilisateur. Par conséquent, les développeurs Javascript n'ont pas besoin de gérer toutes les complexités du développement thread-safe. – SLaks

+0

tester ma solution de réponse s'il vous plaît – CuSS

1

Je suis d'accord avec @SLaks sur celui-ci. Vous devriez utiliser les rappels de jQuery pour des animations données pour créer votre animation synchrone. Vous pouvez prendre tout ce que vous avez essentiellement pour votre animation en cours et le diviser comme ceci:

$yourClass = $('.yourClass'); 
$yourClass.animate({ 
    width: "70%" 
}, 'slow', null, function() { 
    $yourClass.animate({ 
     opacity: 0.4 
    }, 'slow', null, function() { 
     $yourClass.animate({ 
      borderWidth: "10px" 
     }); 
    }); 
}); 
+0

Vous comprenez probablement à quoi cela ressemblerait quand il échelonnerait à 20 actions ... voir aussi ma réponse à @SLaks. –

+0

Si vous n'aimez pas son apparence, essayez de ne pas indenter les rappels (ou seulement de les mettre un peu en retrait). C'est la seule façon de le faire. – SLaks

2

jQuery fournit un rappel « étape » pour sa méthode .animate(). Vous pouvez brancher dans ce pour faire des animations synchrones:

jQuery('#blat').animate({ 
    // CSS to change 
    height: '0px' 
}, 
{ 
    duration: 2000, 
    step: function _stepCallback(now,opts) { 
    // Stop browser rounding errors for bounding DOM values (width, height, margin, etc.) 
    now = opts.now = Math.round(now); 

    // Manipulate the width/height of other elements as 'blat' is animated 
    jQuery('#foo').css({height: now+'px'}); 
    jQuery('#bar').css({width: now+'px'}); 
    }, 
    complete: function _completeCallback() { 
    // Do some other animations when finished... 
    } 
} 
+2

Le rappel d'étape n'a rien à voir avec la question. Le rappel complet est exactement ce que disent les autres réponses. – SLaks

+0

Il essaie d'exécuter une animation après l'autre finit. Il n'essaye pas d'animer deux éléments à la fois. – SLaks

+0

Mes excuses - mon cerveau a inséré un "un" où il n'y en avait pas un! – shuckster

6

Je pense que vous devriez jeter un oeil à la méthode jQuery queue().

Non seulement le document de queue() explique-t-il que les animations jQuery ne bloquent pas vraiment l'interface utilisateur et les mettent en file d'attente les unes après les autres.

Il fournit également un moyen de faire vos animations et les appels de fonction séquentielle (ce qui est ma meilleure compréhension de ce que vous entendez par « synchrone »), comme:

$("#myThrobber") 
    .show("slow")     // provide user feedback 
    .queue(myNotAnimatedMethod) // do some heavy duty processing 
    .hide("slow");    // provide user feedback (job's 

myNotAnimatedMethod() { // or animated, just whatever you want anyhow... 
    // do stuff 
    // ... 

    // tells #myThrobber's ("this") queue your method "returns", 
    // and the next method in the queue (the "hide" animation) can be processed 
    $(this).dequeue(); 

    // do more stuff here that needs not be sequentially done *before* hide() 
    // 
} 

Ceci est bien sûr surpuissant avec traitement asynchrone; mais si votre méthode est en fait une ancienne méthode javascript synchrone, cela pourrait être le moyen de le faire.

Hope this helps, et désolé pour mon pauvre anglais ...

+0

signifie synchrone 'fwrite (big_data)' retourne AFTER 'fwrite' fini d'écrire. Les moyens asynchrones 'fwrite' retourneraient immédiatement, et l'écriture des grosses données se ferait en parallèle/à un autre moment. –

+0

Ensuite, je pense que j'ai bien compris: si vous voulez que l'animation de $ ("# myThrobber") soit exécutée de manière synchrone après fwrite (big_data), vous pouvez le faire avec les deux instructions suivantes: (1) $ ("#myThrobber"). queue (fwrite (big_data)). animate (// peu importe); ET (2) terminez la méthode fwrite() avec $ ("# myThrobber"). Dequeue(); NB: mon échantillon était erroné lors de l'appel $ (this) .dequeue(); il devrait indiquer: $ ("# myThrobber"). Dequeue(); J'ai oublié que comme j'ai créé cet échantillon à partir du code où j'avais besoin de .queue (jQuery.proxy (myNotAnimatedMethod, this)) Désolé pour cette confusion. –

0

Je suis tombé sur ce http://lab.gracecode.com/motion/ vraiment facile à utiliser et fonctionne très bien en combinaison avec jquery.

EDIT Les liens semblent morts. Si j'ai suivi la trace de l'archive wayback correctement, le code est à https://github.com/feelinglucky/motion

+0

Je souhaite qu'il avait la documentation en anglais. Merci quand même. –

+2

@Elazar: Vous pourriez avoir google le traduire; le rend un peu compréhensible;) –

0

jQuery peut faire des animations synchrones.Check this out:

function DoAnimations(){ 
    $(function(){ 
    $("#myDiv").stop().animate({ width: 70 }, 500); 
    $("#myDiv2").stop().animate({ width: 100 }, 500); 
    }); 
} 
+1

Vous avez orthographié "fonction" et "DoAnimations" faux ... –

+1

@ChrisFrancis Juste faire la correction. – Mike

+1

C'est séquentiel, pas synchrone – SLaks

0

Voici un module que j'ai assemblé il y a quelques temps pour aider à exécuter séquentiellement des animations.

Utilisation:

var seq = [ 
    { id: '#someelement', property:'opacity', initial: '0.0', value:'1.0', duration:500 }, 
    { id: '#somethingelse', property:'opacity', value:'1.0', duration: 500 } 
]; 

Sequencer.runSequence(seq); 

var Sequencer = (function($) { 
    var _api = {}, 
     _seq = {}, 
     _seqCount = 0, 
     _seqCallback = {}; 

    function doAnimation(count, step) { 
     var data = _seq[count][step], 
      props = {}; 

      props[data.property] = data.value 

     $(data.id).animate(props, data.duration, function() { 
      if (step+1 < _seq[count].length) { 
       doAnimation(count, ++step); 
      } else { 
       if (typeof _seqCallback[count] === "function") { 
        _seqCallback[count](); 
       } 
      } 
     }); 
    } 

    _api.buildSequence = function(id, property, initial, steps) { 
     var newSeq = [], 
      step = { 
       id: id, 
       property: property, 
       initial: initial 
      }; 

     $.each(steps, function(idx, s) { 
      step = {}; 
      if (idx == 0) { 
       step.initial = initial; 
      } 
      step.id = id; 
      step.property = property; 
      step.value = s.value; 
      step.duration = s.duration; 
      newSeq.push(step); 
     }); 

     return newSeq; 
    } 

    _api.initSequence = function (seq) { 
     $.each(seq, function(idx, s) {    
      if (s.initial !== undefined) { 
       var prop = {}; 
       prop[s.property] = s.initial; 
       $(s.id).css(prop); 
      }    
     }); 
    } 

    _api.initSequences = function() { 
     $.each(arguments, function(i, seq) { 
      _api.initSequence(seq); 
     }); 
    } 

    _api.runSequence = function (seq, callback) { 
     //if (typeof seq === "function") return; 
     _seq[_seqCount] = []; 
     _seqCallback[_seqCount] = callback; 

     $.each(seq, function(idx, s) { 

      _seq[_seqCount].push(s); 
      if (s.initial !== undefined) { 
       var prop = {}; 
       prop[s.property] = s.initial; 
       $(s.id).css(prop); 
      } 

     }); 


     doAnimation(_seqCount, 0); 
     _seqCount += 1; 
    } 

    _api.runSequences = function() { 
     var i = 0. 
      args = arguments, 
      runNext = function() { 
       if (i+1 < args.length) { 
        i++; 
        if (typeof args[i] === "function") { 
         args[i](); 
         runNext(); 
        } else { 
         _api.runSequence(args[i], function() { 
          runNext(); 
         }); 
        } 
       } 
      }; 

     // first we need to set the initial values of all sequences that specify them 
     $.each(arguments, function(idx, seq) { 
      if (typeof seq !== "function") { 
       $.each(seq, function(idx2, seq2) { 
        if (seq2.initial !== undefined) { 
         var prop = {}; 
         prop[seq2.property] = seq2.initial; 
         $(seq2.id).css(prop); 
        } 
       }); 
      } 

     }); 

     _api.runSequence(arguments[i], function(){ 
      runNext(); 
     }); 

    } 

    return _api; 
}(jQuery));