JQuery анимированный обратный вызов не выполняется до последнего цикла

Я сделал небольшой тестовый код, используя плагин JQuery для анимации.

Цель сценария - сделать фотографию башни, повернуть ее на 90 градусов к пользователю, переключиться на другое изображение башни и повернуть еще 90 градусов, чтобы лежать на экране. Проблема заключается в том, что после первого поворота на 90 градусов изображение полностью исчезает до тех пор, пока цикл for не завершится, прежде чем выполнить окончательное отражение в качестве второго изображения. Я надеюсь, что он будет переворачиваться непрерывно, пока цикл не закончится.

Я полагаю, это как-то связано с замыканиями и областью действия...

Javascript:

$(function() {
 for (var i = 0; i < 10; i++) {
  $('#test_flip')
   .css('background-image', 'url("tower1.jpg")')
   .transition({
    rotateY: '90deg'
   }, function() {
    $('#test_flip')
     .css('background-image', 'url("tower2.jpg")')
     .transition({
      rotateY: '180deg'
     });
   });
 };
});

jsfiddle: http://jsfiddle.net/ce9b9aja/

1 ответ

Решение

Проблема заключается в том, что вызовы цикла for .transition 10 раз подряд. Звонки queued в очереди jQuery (что делается негласно транзитом.js), но они не ставятся в очередь в том порядке, в котором вы ожидаете.

Возьмите следующий пример:

$(function () {
    $('#test').transition({x:40}, function () {
        $(this).transition({y:40});
    })
    
    $('#test').transition({scale:0.5}, function() {
        $(this).transition({skewX:"50deg"});
    });
});
#test {
    width: 10em;
    height: 10em;
    background-color: gray;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://ricostacruz.com/jquery.transit/jquery.transit.min.js"></script>
<div id="test"></div>

В этом примере первый переход x:40 будет выполнен мгновенно, потому что нет очереди. Несмотря на то, что он выполняется мгновенно, так как это анимация, он будет использовать некоторую форму setTimeout или же setInterval и не будет завершено в transition вызов метода. Следовательно, scale:0.5 Переход будет называться в то время как x:40 переход по-прежнему анимируется, что ставит его в очередь до y:40 ставится в очередь.

Таким образом, порядок очереди

x:40 -> scale:0.5 -> y:40 -> skewX:50deg

Точно так же ваш код создает следующую очередь:

rotateY:90deg -> ... -> rotateY:90deg -> rotateY:180deg -> ... -> rotateY:180deg

Таким образом, поведение вашего кода. Поворачивает изображение 90deg сначала он делает это еще 9 раз, что ничего не меняет визуально (отсюда и "пауза"). Затем он меняет изображение и вращает его 180deg и делает это еще 9 раз также.

Одним из решений может быть создание рекурсивной функции с помощью обратного вызова .transition функция. Пример реализован ниже:

$(function() {
    FlipMe($('#test_flip'), "http://i.imgur.com/tYYtwbi.jpg", "http://i.imgur.com/G4CvJpc.jpg", 10)
});

function FlipMe($el, image1, image2, times) {
    $el.css('background-image', 'url("'+image1+'")')
        .transition({rotateY: '90deg'}, function() {
                $el.css('background-image', 'url("'+image2+'")')
                .transition({rotateY: '180deg'}, function() {
                    if(times > 0) {
                        FlipMe($el, image2, image1, times - 1);
                    }
                });
    });
}

Обновленная скрипка здесь: http://jsfiddle.net/ce9b9aja/1/

Приведенный выше код использует исключительно функции обратного вызова для определения порядка событий. Когда первый переход завершен, функция обратного вызова "поставит в очередь" следующий переход, который будет выполнен мгновенно, поскольку в очереди больше ничего не будет. И так далее.

Другие вопросы по тегам