Frage

I need to change images in a slide of an image slider.

Every slide contains two images which will change after 3 seconds.

So, the slide comes with the first image, after 3 seconds it changes the first image to the second image and after another 3 seconds ( so 6 seconds total ) the current slide goes and the next slide comes.

My idea is to use setTimeOut function and to call every 3 seconds another image. So after 3 seconds fadeOut() the first image and fadeIn() the second.

I tried this using cycle2 and its cycle-after and cycle-before event:

$('.slide .center img:nth-child(2)').hide(); // hide all slides second images

$('#slides').cycle({
    fx: 'scrollHorz',
    slides: '>.slide',
    timeout: 6000,
    prev: '#prev',
    next: '#next'
});

$('#slides').on('cycle-before', function(event, optionHash){
    setTimeout(function(){
         $('.slide:eq('+optionHash.currSlide+') > .center > img:first-child').fadeOut(1000);
         console.log($('.slide:eq('+(optionHash.currSlide)+')').attr('slideNum'));
    },1000)

    setTimeout(function(){
        $('.slide:eq('+optionHash.currSlide+') > .center > img:nth-child(2)').fadeIn();
        console.log($('.slide:eq('+(optionHash.currSlide)+')').attr('slideNum'));
    },2000)
});

$('#slides').on('cycle-after', function(event, optionHash, outgoingSlideEl, incomingSlideEl, forwardFlag) {
    $('.center img:first-child',outgoingSlideEl).show();
    $('.center img:nth-child(2)',outgoingSlideEl).hide();
});

JSFiddle

But this doesn't work as I expected. It doesn't change the images and it breaks on next and prev button. If you see the console, you'll see that it doesn't trigger the current slide.

Any help is appreciated.

War es hilfreich?

Lösung

If you inspect the HTML code generated by JavaScript, you'll notice that Cycle2 duplicates the first slide and makes it invisible. The reason for this is beyond me, but at least we can easily work around it.

Secondly, you should trigger the fade-in/fade-out animation in cycle-after. If this is done in cycle-before, the setTimeout counter begins while the slideshow is still transitioning to the next slide. Another problem is that in cycle-after, optionHash.currSlide is set to the previous slide...

In order to work around all those issues, we have to calculate the index of the currently visible slide like so:

var visibleSlide = ((optionHash.currSlide + 1) % optionHash.slideCount) + 1;

Regarding the broken previous/back buttons, it actually should be enough to completely stop the fade-in/fade-out animation and reset it when one of the buttons is clicked. However, when the prev button is clicked, the index calculation has to be adjusted (-1 instead of +1, see code below).

Furthermore, we have to trigger the fade-in/fade-out animation "manually" for the very first slide right after initialization of the slideshow. To do this, we can use the cycle-initialized event combined with the logic from cycle-after.

I guess code says more than a thousand words, so here is my suggestion:

$(".slide img:nth-child(2)").hide();

// Workaround for first slide right after initialization
// Handler has to be set before initialization, otherwise it might never be called!
$("#slides").on("cycle-initialized", function(event, optionHash){
    // Pretend the slideshow just transitioned from the last slide to the first
    onCycleAfter(optionHash.slideCount-1, optionHash.slideCount);
});

$("#slides").cycle({
    fx: "scrollHorz",
    slides: ".slide",
    timeout: 6000,
    prev: "#prev",
    next: "#next"
});

var timeout, prevClicked = false;
$("#slides").on("cycle-after", function(event, optionHash){
    onCycleAfter(optionHash.currSlide, optionHash.slideCount);
});

$("#slides").on("cycle-prev", function(){
    prevClicked = true;
});

function onCycleAfter(currSlide, slideCount) {
    // Reset slides
    $(".slide img:first-child").show();
    $(".slide img:nth-child(2)").hide();

    // Reset animation
    clearTimeout(timeout);
    $(".slide img").finish();

    // Calculate current slide (with workaround for prev button)
    var visibleSlide;
    if (prevClicked) {
        visibleSlide = ((currSlide - 1 + slideCount) % slideCount) + 1;
        prevClicked = false;
    }
    else {
        visibleSlide = ((currSlide + 1) % slideCount) + 1;
    }

    // Trigger new animation
    timeout = setTimeout(function(){
        var slideImages = $(".slide").eq(visibleSlide).find("img");
        slideImages.eq(0).fadeOut(1000, function(){
            slideImages.eq(1).fadeIn(1000);
        });
    }, 1000);
}

DEMO (JSFiddle)

Andere Tipps

Edit:

Seems like currSlide is ok but somehow the name is wrong due to race condition caused by setTimeOut. See this fork: http://jsfiddle.net/pMX7D/3/

Output I got:

1=> fadeIN /_display/ (line 63)
second /_display/ (line 56)
2=> fadeOut /_display/ (line 57)
second /_display/ (line 62)
2=> fadeIN 

// 3 never gets focus

Original

It is working. Output from my console after clicking randomly on prev and next button:

// first or second = slide data I beileve
[cycle2] --c2 init--
jquery....min.js (line 7) 
first
/vucko...5/show/ (line 56)
first
/vucko...5/show/ (line 61)
[cycle2] cycle-next
jquery....min.js (line 7)
first
/vucko...5/show/ (line 56)
[cycle2] cycle-next
jquery....min.js (line 7)
first
/vucko...5/show/ (line 61)
second
/vucko...5/show/ (line 56)
[cycle2] cycle-prev
jquery....min.js (line 7)
second
/vucko...5/show/ (line 61)
[cycle2] cycle-prev
jquery....min.js (line 7)
first
/vucko...5/show/ (line 56)
second

I am using: Firefox 16.0.2 in windows.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top