clearTimeout во время анимации галереи - PullRequest
0 голосов
/ 10 августа 2011

Я создал галерею с автовоспроизведением.

Когда галерея перестает работать с анимацией, и мы наводим курсор на галерею, все работает как положено.

Но я получаю странную проблему:

Пока анимация галереи -> при наведении на галерею, clearTimeout, кажется, не работает правильно и при отпускании мыши галерея ведет себя странно
или происходит странный конфликт Я не могу понять и решить. Я вернулся в другую галерею, которую создал пару дней назад с похожей функциональностью, и столкнулся с той же проблемой.

Я упускаю что-то важное здесь

ГАЛЕРЕЯ В ВОПРОСЕ: jsFiddle

var myTimeOut;

/////// ANIMATION /////////////   
    function animation(cb){         
            $('#slider').animate({left: '-=600' },800, cb);
    }      
    /////// AUTO SLIDE ////////////
    function auto() {
        myTimeOut = setTimeout(function() {
            animation(function(){
                auto();                   
            });   
        }, 2000);
    }
    auto();

и как я пытаюсь его приостановить:

    ///// MOUSE actions //////////   
    $('#galcontainer').mouseenter( function () {
      clearTimeout(myTimeOut);
    });
    $('#galcontainer').mouseleave( function () {
     auto();
    });

EDIT

Добавление 'флажка при наведении курсора' (как предложено в ответах) работает почти замечательно, но небольшая ошибка, использующая это решение, видна, когда 'fast mouseenter / mouseleave В ТЕЧЕНИЕ анимации.
Решением этой проблемы может быть добавление $ ('# slider'). Stop () в mouseleave. Не отличное решение.
Что еще я могу сделать?

Ответы [ 7 ]

3 голосов
/ 15 августа 2011

Когда анимация выполняется, иногда событие mouseout не срабатывает, поэтому переменная pause не установлена ​​в false.когда следующее событие мышки срабатывает, так как пауза не false, он снова установит таймаут.Я просто позаботился о том, чтобы мы очистили любой предыдущий таймаут перед установкой нового.

Посмотрите на это рабочее демо.

http://jsfiddle.net/8Lzxs/3/

1 голос
/ 27 августа 2013

Я обнаружил, что прокрутка (что тоже является своего рода анимацией) в iOS 6, похоже, вызывает ту же проблему: таймауты не очищаются надежно, пока прокручивается представление.

Я считал это ошибкой iOS и - в моем случае - нашел решение, не использующее set и clearTimeout.

Эта проблема не может быть воспроизведена в (нескольких) Android Stock Browser и Chrome.

1 голос
/ 10 августа 2011

Не вдаваясь слишком глубоко в ваш код, я исправил его, добавив пару дополнительных проверок.

Сначала я сделал это, чтобы не беспокоиться о замене идентификатора timeOut.Я использую массив в случае, когда несколько событий накладываются друг на друга, и очищаю все таймауты в этом массиве.

Во-вторых, я добавил значение stop () и сделал так, чтобы анимация не работалаВыполнить, если остановлено, имеет значение true.

Вот скрипка с моими изменениями: http://jsfiddle.net/6WhNw/

1 голос
/ 10 августа 2011

Не работает, если ваша мышь входит во время анимации. Это потому, что таймер уже сработал и конец анимации начнет новый, когда он завершится. Наименьшее количество переписывания, которое я могу придумать, чтобы решить эту проблему, было бы установить глобальный флаг, когда вы зависли, что автоматическая функция проверяет, чтобы не запускать новую анимацию, если этот глобальный флаг установлен.

Вы можете увидеть решение hoverFlag здесь: http://jsfiddle.net/jfriend00/EaKnj/.

Интересным примером для тестирования является включение мыши при запуске анимации.

1 голос
/ 10 августа 2011

Проблема в том, что во время анимации нет времени ожидания для остановки.Один тайм-аут уже сработал, а другой не создается до завершения анимации.Из-за этого при наведении курсора на анимацию продолжается.Вы можете решить это с помощью флага, чтобы указать, должна ли анимация быть остановлена.Если флаг установлен, авто возвращается и не устанавливает другой тайм-аут.

http://jsfiddle.net/PXVSW/6/

0 голосов
/ 14 августа 2011

Проблема : на mouseenter во время анимации, обратный вызов jQuery .animate() cb уже находится в очереди (даже если вызывается clearTimeout, еще один auto() будет вызван, что вызовет последующие запуски и т. д.).

Использование setInterval и использование всех этих обратных вызовов является ключом:

jsFiddle demo

$(function(){                 // DOM ready shorthand
    var $sli =  $("#slider"), // Cache elements you plan to reuse
        galW =  $('#gallery').width(),
        imgN =  $sli.find('img').length,
        counter = 0,          // set it to index 0!
        itv;                  // setInterval (scope var)
    
    $sli.width(galW * imgN);

    function anim() {
      ++counter; counter%=imgN;                       // Incr.counter; and wrap-around
      $sli.stop().animate({left: -galW*counter},900); // width*counter = px position
    }
    function autoSlide() {
        itv = setInterval(anim, 3000);
    }
    autoSlide();
    
    ///// MOUSE STATE //////////   
    $sli.hover(function(){ clearInterval(itv); }, autoSlide);
});
#galcontainer{
    position:relative;
    margin:20px auto;
    width:600px;
}
#gallery{
    position:relative;
    overflow:hidden;
    width:600px;
    height:240px;
}
#slider{
    position:absolute;
    top:0px;
    left:0px;
}
#slider img{
    float:left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="galcontainer">    
    <div id="gallery">    
        <div id="slider">
            <img src="http://dummyimage.com/600x240/479/fff"/>
            <img src="http://dummyimage.com/600x240/636/fff"/>
            <img src="http://dummyimage.com/600x240/587/fff"/>
            <img src="http://dummyimage.com/600x240/447/fff"/>
        </div>     
    </div>   
</div>

(Помимо примечаний относительно исходного (пока не измененного) кода)

Переменная direction с "+=" и "0-" не нужна, так как есть только одно направление, поэтому используйте индексированный counter = 0, а затем переходите / сбрасывайте с помощью оператора Reminder %. Кроме того,

        animation(function(){
            auto();                   
        }); 

можно записать как:

       animation(auto);

, поскольку auto уже является функцией.

///// MOUSE STATE //////////   
$('#galcontainer').mouseenter( function () {
  clearInterval(myTimeOut);
});
$('#galcontainer').mouseleave( function () {
 auto();
});

можно использовать с методом .hover(fn1, fn2) (как в примере выше)

0 голосов
/ 10 августа 2011

Вы должны использовать setInterval вместо setTimeout. Так как анимация вызывает обратный вызов, она будет вызывать анимацию снова и снова.

http://jsfiddle.net/PXVSW/7/

var galW =  $('#gallery').width() ,
    imgN =  $('#slider img').length ,
    direction,      // direction ( -=  or  0- ) // set initially to 'null','undefined'
    counter = 1,    // counter
    myTimeOut;       // global setTimeout

$('#slider').width(galW * imgN);

/////// ANIMATION /////////////   
function animation(){                 // cb : makes animation accept a callback
        $('#slider').animate({left: direction+''+galW},800);
}  

/////// AUTO SLIDE ////////////
function auto() {
    myTimeOut = setInterval(function() {
        if ( counter != imgN){           // if counter != '4' (N of Images)
            counter++                    // add '1' to counter
            direction = '-=';            // set direction to go 'left' 
        }
        else{
            counter = 1;
            direction = '0-';            // trick - to bring slider to '0px' left (start position)
        }
        animation();   
    }, 2000);
}
auto();

///// MOUSE STATE //////////   
$('#galcontainer').mouseenter( function () {
  clearInterval(myTimeOut);
});
$('#galcontainer').mouseleave( function () {
 auto();
});
...