Slider- setInterval odlicza ale nie wykonuje się

0

Witam

Mam pewien problem ze sliderem na stronie. Slider działa na poleceniu setInterval. Jeśli strona jest aktywna to wszystko jest ok. Problem pojawia się gdy przechodzę do innej zakładki. Gdy strona ze sliderem nie jest aktywna funkcja setInterval odlicza czas lecz nie wykonuje się. W wyniku tego gdy powrócę na stronę ze sliderem funkcja setInterval (a właściwie funkcja slide();) wykonuje się tyle razy z rzędu ile razy się "zbuforowała" bez odstępu czasowego (na tyle szybko na ile pozwalają jej ustawienia efektów przejścia).

<script type="text/javascript">
 
var banners = 3;
var limit = (banners-1)*628;
var szer = 628;
var licznik = 0;
 
$(function () {
        setInterval("slide();",6000);
        $("#slider_next").click(function(){next();});
        $("#slider_prev").click(function(){back();});
});
 
function slide()
{
        if(licznik<(banners-1))
        {next();}
        else
        {prev();}
}
 
function prev()
{
        $("#slider_main").animate({'opacity':'0'},100);
        $("#slider_main").animate({'left':'0px'},0);
        $("#slider_main").delay(100).animate({'opacity':'1'},100);        
        licznik = 0;
}
 
function prev2()
{
        $("#slider_main").animate({'opacity':'0'},100);
        $("#slider_main").animate({'left':'-'+limit+'px'},0);
        $("#slider_main").delay(100).animate({'opacity':'1'},100);        
        licznik = (banners-1);
}
 
 
function next()
{
        if(licznik < (banners-1))
        {
                $("#slider_main").animate({'opacity':'0'},100);
                $("#slider_main").animate({'left':'-='+szer+'px'},0);
                $("#slider_main").delay(100).animate({'opacity':'1'},100);
                licznik++;
        }
        else
        {prev();}
}
 
function back()
{
        if(licznik > 0)
        {
                $("#slider_main").animate({'opacity':'0'},100);
                $("#slider_main").animate({'left':'+='+szer+'px'},0);
                $("#slider_main").delay(100).animate({'opacity':'1'},100);
                licznik=licznik-1;
        }
        else
        {prev2();}
}
0

Zamiast setInterval, użyj pseudorekurencyjnego setTimeout(). Niech nowa funkcja wykonywana po załadowaniu drzewa dokumentu wygląda tak:

var SLIDE_DELAY = 6000; // uwaga, zły kod! ale lepszy od tego, niż był
$(function () {
        slideAfterDelay();
        $("#slider_next").click(next);
        $("#slider_prev").click(back);
});

function slideAfterDelay() {
        setTimeout(slide,SLIDE_DELAY);
}

Zauważ, że trochę ją uprościłem.

Wydzieliłem funkcję slideAfterDelay -- wywołuje slide() po upływie sześciu sekund za pomocą setTimeout(), ale robi to raz, a nie tak jak setInterval, które odpalałoby funkcję co każde 6 sekund. Funckja slideAfterDelay() to jedna linijka, ale napisalibyśmy ją zaraz drugi raz, a chcemy uniknąć powtórzeń.

Wywaliłem niepotrzebne funkcje anonimowe z .click(), a string przekazany do setInterval (a teraz setTimeout -- wywołuje się je podobnie) zamieniłem na bezpośrednie odniesienie do funkcji slide. String był bezsensowny i był ukrytym eval()-em.

Następnie, na końcu funkcji slide dodaj po prostu wywołanie slideAfterDelay(). Dzięki temu funkcja slide() sama zadba o to, by zostać wywołana w 6 sek. po zakończeniu bieżącego wywołania. Powinno być to odporne na wszelkie buforowanie, bo zanim funkcja na serio nie zostanie wywołana, to przeglądarka nie będzie nawet wiedziała, że funkcja chce się znowu wywołać za kolejne 6 sekund.

Proponowane przeze mnie rozwiązanie ma pewne minusy. Teraz np. nie da się wywołać funkcji slide() raz. Ona już zawsze będzie rekurencyjna. Dlatego wypadałoby jej zmienić nazwę. Albo raczej: dodać kolejną funkcję, np. slide_r (r jak rekurencja) i to ją wywoływać w slideAfterDelay, i to tam przenieść wywołanie slideAfterDelay z końca funkcji slide. Nie chciałem Ci jednak mącić w pierwszym kroku.

0

Zmieniłem kod wg. powyższych wskazówek i problem pozostał. Dodatkowo zauważyłem, że w IE nie występuje (korzystam z Chrome). Coś musi być nie tak z poleceniami jQuery ponieważ do wyżej przedstawionego slidera dodałem jeszcze przyciski przenoszące do wybranego bannera. Przyciski te zmieniają kolor tła w czasie przejścia slide(); a polecenie za to odpowiedzialne siedzi w funkcji next(); i back(); a więc tej samej co odpowiada za efekt "slide". Przyciski zmieniają się prawidłowo i nie występuje w ich przypadku w/w "buforowanie". Oto kod dodany do next(); na początku if przed efektami animate.

$("#sgo"+(btn)).css({'background':'#cd0000'});
btn++;
$("#sgo"+(btn)).css({'background':'#395994'});

Może to po prostu ustawienia mojej przeglądarki? Slider którego dotyczy problem znajduje się na stronie: www.highland-sklepy.pl

0

W takim razie, kod JavaScript jednak jest wykonywany również gdy jesteśmy przełączeni na inną kartę.

Problem na pewno da się jakoś rozwiązać. W najgorszym razie możemy spróbować wykryć, czy jesteśmy na naszej karcie i tylko wtedy wykonywać właściwe slide'owanie (w przeciwnym wypadku -- poczekać jeszcze trochę czasu i znowu sprawdzić, czy jesteśmy na tej karcie).

Nawet chciało mi się to zdebugować, bo o tym problemie słyszałem, a nie miałem wcześniej okazji się nim zająć. Ale ten skrypt masz dołączony inline w HTML (zamiast porządnie, w osobnym pliku), w dodatku mój debugger nie widzi tam znaków nowych linii... no i mi się odechciało ;). Polecam Ci wyciągnąć to do osobnego pliku i zadbać o nowe linie, to łatwiej się to będzie debugowało. Nie wiem, czy przeglądarki mogą buforować w ten sposób tylko wywołania DOM, a puszczać cały inny JS -- przecież ten "inny JS" może najpierw modyfikować, a potem odczytywać DOM i wtedy otrzymałby bezsensowne wyniki (nie widziałby zmian). Na odległość ciężko to ocenić, to raczej trzeba po prostu samodzielnie zdebugować -- ustawić breakpointy w funkcji slide() i zobaczyć, co tam się tak naprawdę dzieje gdy się przełączymy z powrotem na kartę.

1 użytkowników online, w tym zalogowanych: 0, gości: 1