nolimits4web / swiper

Most modern mobile touch slider with hardware accelerated transitions
https://swiperjs.com
MIT License
39.9k stars 9.75k forks source link

appendSlide is not appending, but prepending for slide duplicates/copies #2575

Closed 7UPascal closed 6 years ago

7UPascal commented 6 years ago

This is a (multiple allowed):

What you did

Since there's a known issue with slides per view, centered slides and loop set to true, I've been trying to build a work-around for my colleague. Just manually appending and prepending slides, when the realIndex reaches a certain number.

During the initialization, we're taking the last 3 slide of our list and moving them to the front (we have 7 slides visible (even if that requires the slidesPerView to be set to 6 to get the visual outcome we want (the outer 2 to be shown only partially), where the active one should be the one in the middle).

When we go back and thus the last slides should be prepended (to make sure we keep having 3 slides prior to the active one), things work fine, using prependSlide(). However, when navigating forward, and trying to the exact same with appendSlide(), the DOM elements aren't moved from the front to the back. Instead, they're just placed in their original positions at the front, meaning we still run into an end slide, instead of there always being 3 after the active slide as well.

Expected Behavior

What we want is for the appendSlide method to place the DOM elements at the end of the list of slides, but it doesn't do that.

Actual Behavior

The elements don't get added to the end of the list. Instead, they seem to be in the place of the original elements.

NOTE: This happens when we try to duplicate the slides only. When we create new slides (i.e. appendSlide("<div class=\"swiper-slide\">test

")), the elements seemingly DO get added at the end.

nolimits4web commented 6 years ago

Do you have a JSFiddle illustrating the issue, or code examples?

7UPascal commented 6 years ago

The general swiper HTML

<div class="swiper-container">
    <div class="swiper-wrapper">

        <div class="swiper-slide">
            <img src="img.jpg" alt=""  class="poster"/>
        </div>

        <div class="swiper-slide">
            <img src="img.jpg" alt=""  class="poster"/>
        </div>

        <div class="swiper-slide">
            <img src="img.jpg" alt=""  class="poster"/>
        </div>

        <div class="swiper-slide">
            <img src="img.jpg" alt=""  class="poster"/>
        </div>

        <div class="swiper-slide">
            <img src="img.jpg" alt=""  class="poster"/>
        </div>

        <div class="swiper-slide">
            <img src="img.jpg" alt=""  class="poster"/>
        </div>

        <div class="swiper-slide">
            <img src="img.jpg" alt=""  class="poster"/>
        </div>

        <div class="swiper-slide">
            <img src="img.jpg" alt=""  class="poster"/>
        </div>

        <div class="swiper-slide">
            <img src="img.jpg" alt=""  class="poster"/>
        </div>

        <div class="swiper-slide">
            <img src="img.jpg" alt=""  class="poster"/>
        </div>

        <div class="swiper-slide">
            <img src="img.jpg" alt=""  class="poster"/>
        </div>

        <div class="swiper-slide">
            <img src="img.jpg" alt=""  class="poster"/>
        </div>

    </div>
</div>

<div class="swiper-button-prev"><i class="fas fa-angle-left"></i></div>
<div class="swiper-button-next"><i class="fas fa-angle-right"></i></div>

The swiper initialization code:

// Coverflow homepage
    var mySwiper = new Swiper ('.swiper-container', {
        effect: 'coverflow',
        grabCursor: true,
        centeredSlides: true,
        slidesPerView: 6,
        // loop: true,
        slideToClickedSlide: true,
        coverflowEffect: {
            rotate: 0,
            stretch: 0,
            depth: 100,
            modifier: 1,
            slideShadows : false,
        },
        navigation: {
            nextEl: '.swiper-button-next',
            prevEl: '.swiper-button-prev',
        },
        breakpoints: {
            640: {
                slidesPerView: 1,
                spaceBetween: 30
            }
        },
        on: {
            init: function ()
            {
                var clones = [];
                for(var i=1; i <= 3; i++)
                // for(var i=1; i <= (this.params.slidesPerView - 1); i++)
                {
                    // Make a duplicate of the end element
                    var duplicate = this.slides[(this.slides.length - i)];

                    clones.push(duplicate);
                }

                this.prependSlide(clones);
            },
        },
    });
    mySwiper.on('slideChangeTransitionEnd',function()
    {
        moveSlides(this);
    });

And finally, the moveSlides function that is called at the end of each transition

function moveSlides(swiper)
{
    var clones = [];

    // Check if we'll still have enough out of focus elements after the transition
    if (swiper.realIndex < swiper.previousIndex) // We need more at the start
    {
        // Determine the amount of slides we need to prepend
        var requiredItems = swiper.previousIndex - swiper.realIndex;

        for(var i=1; i <= requiredItems; i++)
        {
            // Make a duplicate of the end element
            var duplicate = swiper.slides[(swiper.slides.length - i)];
            clones.push(duplicate);
        }

        swiper.prependSlide(clones);
    }
    else if(swiper.realIndex > swiper.previousIndex)
    {
        // Determine the amount of slides we need to prepend
        var requiredItems = swiper.realIndex - swiper.previousIndex;

        for(var j=0; j < requiredItems; j++)
        {
            // Make a duplicate of the end element
            var duplicate = swiper.slides[j];
            clones.push(duplicate);
        }

        for (var k = 0; k < j; k++)
        {
            swiper.removeSlide(k);
        }

        // swiper.appendSlide('<div class="swiper-slide">test</div>');
        swiper.appendSlide(clones);

        swiper.slideTo(swiper.previousIndex, 0);
        swiper.update();
    }
}
7UPascal commented 6 years ago

The place where the issue occurs is that swiper.appendSlide(clones) line near the end

nolimits4web commented 6 years ago

Looks like calling swiper.slideTo(swiper.previousIndex, 0); produces the infinite loop, as it will also triggers slideChangeTransitionEnd event. Try to call it with last false argument swiper.slideTo(swiper.previousIndex, 0, false);

7UPascal commented 6 years ago

Thanks for the tip. It didn't quite solve the problem, however... I did manage to solve it.

That whole slideTo was added in an earlier stage, where everytime we tried to move forward, it would go 2 steps forward. Therefore I added the part where it slides back to the previous index at the end. However, apparently the code had been improved in between. So now it didn't need that line anymore.

It also doesn't need the update() after that anymore. So it seems like at this point we just did too much.

Thanks again for the help, though. Much appreciated!