2011-02-09 17 views
10

Mam wiele animacji na jednym obiekcie i muszę zatrzymać konkretną animację, a nie wszystkie. Wygląda na to, że metoda .stop() nie może tego zrobić.Zatrzymywanie określonych animacji jQuery

Na przykład podczas animowania krycia i szerokości jednocześnie może być konieczne anulowanie animacji krycia przy wypełnianiu animacji szerokości. Wydaje się, że nie jest to możliwe, ale mam nadzieję, że ktoś zna sztuczkę lub wywołanie API, którego mi brakuje.

Uwaga: Nie mówię o kolejce animacji, szukam do animowania wiele atrybutów jednocześnie z możliwością zatrzymania niektórych z tych atrybutów animacji po oni już zaczęli

+0

myślałem że nie byłoby to sposób za pomocą niestandardowej nazwie kolejki, ale nie wydaje się, podobnie jak '.Zatrzymaj()' sposób można kierować konkretną kolejkę (o ile mogę powiedz mimo to). – user113716

+0

Na razie złożyłem wniosek o dodanie tej funkcji: http://bugs.jquery.com/ticket/8227 – slifty

+0

Jakie są kryteria zatrzymania animacji? Czy jest oparty na działaniu użytkownika? – Jeff

Odpowiedz

8

Nienawidzę być facetem, który odpowiada na własne pytanie (bardzo dziękuję za szczegółowe odpowiedzi i wkładanie w to mocy mózgu!), Ale znalazłem bezpośrednią odpowiedź. Najwyraźniej istnieje parametr dla metody .animate() o nazwie "queue", która domyślnie jest równa true, ale można ustawić wartość false, aby animacja miała miejsce natychmiast.

Oznacza to, że ustawiając kolejkę na wartość false, można uruchamiać wiele animacji, korzystając z oddzielnych wywołań, bez konieczności oczekiwania na zakończenie poprzedniej. Co więcej, jeśli spróbujesz uruchomić animację dla nieruchomości, która jest już animowana, druga zastąpi pierwszą. Oznacza to, że możesz przerwać animację nieruchomości, po prostu "animując" ją do jej bieżącej wartości przez czas 0, używając kolejki "false".

Przykład:

$myElement = $("#animateElement"); 
$myElement.animate({width: 500}, {duration: 5000}); 
$myElement.animate({height: 500}, {duration: 5000, queue: false}); 
// ... Wait 2 seconds ... 
$myElement.animate({width: $myElement.width()}, {duration: 0, queue: false}); 

Another option został zaproponowany przez łaskawego jQuery specjalista, którzy odpowiedzieli na moją prośbę wzmocnionego. Wykorzystuje to możliwość użycia funkcji krokowej w animacji (funkcje krokowe są wywoływane w każdym punkcie animacji i można manipulować parametrami animacji w oparciu o dowolne kryteria). Chociaż to również mogło rozwiązać problem, czułem, że jest on dużo bardziej brudny niż opcja "kolejka: fałsz".

3

Po przemyśleniu o tym trochę trudniej o tym, zdałem sobie sprawę, że to, co próbujesz zrobić, nie jest łatwe do wykonania ze względu na sposób, w jaki animacje są obsługiwane w jQuery.

Ponieważ animacje są zarządzane przez kolejkę, nie można uruchomić animacji współbieżnych na tym samym elemencie, nie będąc w tej samej funkcji.

To znaczy,

$(element).animate(aThing, aTime); 
      .animate(anotherThing, anotherTime); 

nie będzie działać równolegle. aThing zakończy się w po upływie pewnego czasu, a następnie innymThing trwającym przez anotherTime.

W ten sposób można osiągnąć jedynie przez wiele zmian mających je w tej samej funkcji:

$(element).animate({aThing: aValue, anotherThing: anotherValue}, aTime); 

Oto krótkie wyjaśnienie, w jaki sposób funkcjonuje anatomii animacji są obsługiwane w ramach jQuery.

Obiekt Timer jest przypisany do elementu przez cały czas trwania animacji:

function t(gotoEnd) { 
    return self.step(gotoEnd); 
} 

t.elem = this.elem; 
jQuery.timers.push(t); 

Po wywołaniu funkcji zatrzymania, usuwa timer z timerów:

// go in reverse order so anything added to the queue during the loop is ignored 
for (var i = timers.length - 1; i >= 0; i--) { 
    if (timers[i].elem === this) { 
     if (gotoEnd) { 
      // force the next step to be the last 
      timers[i](true); 
     } 

     timers.splice(i, 1); 
    } 
} 

Więc tam nie ma możliwości usunięcia określonej właściwości funkcji animacji, ponieważ sam timer został zabity.


Jedynym sposobem mogę myśleć o realizacji tego byłoby śledzić czas rozpoczęcia i czas trwania, ponownie enqueuing animację i zatrzymywanie bieżącej.

var start = $.now(); 
var duration = 5000; 

$(element).animate({opacity: '0.5', width: '500px'}, duration); 

...

var remaining = duration - ($.now() - start); 
$(element).animate({opacity: '0.5', remaining) 
      .stop(); 
+0

Wielkie dzięki za odpowiedź! Może nie do końca rozumiem, ale wygląda na to, że ten kod spowoduje animację szerokości trwającą 5 sekund, w którym to momencie rozpocznie się animacja krycia. Muszę mieć możliwość jednoczesnego uruchamiania animacji szerokości i przezroczystości (tzn. Zmieniają się zarówno szerokość, jak i krycie), z możliwością zatrzymania jednego lub drugiego przed zakończeniem bez zatrzymywania obu. – slifty

+0

W porządku, teraz poprawiłem swoją odpowiedź, ponieważ faktycznie lepiej rozumiem twoje pytanie:). –

+0

Cześć Ian - Chciałem tylko bardzo podziękować za tak szczegółową odpowiedź. Udało mi się znaleźć bezpośrednie rozwiązanie, które nie wymaga żadnego śledzenia, więc niestety nie mogę podać tagu odpowiedzi :(Mam nadzieję, że pewnego dnia będziesz mógł skorzystać z tego rozwiązania! – slifty

1

Zamiast jednej animacji, można podzielić ją na kilka mniejszych animacji (tj animować krycie od 0-20%, następnie animować od 20-40%, a następnie 40-60% itp.) I zamiast animacji, po prostu nie uruchamiasz go ponownie?

0

Używam plugin jQuery cycle do animacji kilkunastu pokazów slajdów na tej samej stronie przy użyciu różnych typów animacji (chusteczki, tasowania, powiększenia itp.). Ja wtedy miałem własną malutką skrypt zanikać obrazy lekko jak unosił się nad każdym Pokaz slajdów:

# This code stops all current animations on an element 

$(".box img").hover(
    function(){ 
     $(this).stop().fadeTo("slow",0.7); 
    }, 
    function(){ 
     $(this).stop().fadeTo("fast",1); 
    } 
); 

Problem został funkcja .stop() także zatrzymanie plugin cyklu Śledzi - moje chusteczki, tasuje i zoomy zatrzymywały gwałtownie w połowie ich animacji, pozostawiając stronę złamaną i nie na miejscu. Rozwiązaniem było zaimplementować kolejkę „false” pomysł:

# This code suited me better - it leaves the other running animations untouched 

$(".box img").hover(
    function(){ 
     $(this).animate({opacity: 0.7}, {duration: 1000, queue: false}); 
    }, 
    function(){ 
     $(this).animate({opacity: 1}, {duration: 250, queue: false}); 
    } 
); 
1

UPDATE 2013

Jak jQuery 1.7 można użyć .animate() o nazwie kolejki i użyj .stop(queuename) zatrzymać tylko te animacje w kolejka.


http://api.jquery.com/stop/