создание плавного бесконечного слайдера карусели из нескольких элементов с использованием javascript - PullRequest
1 голос
/ 20 января 2020

Я создаю слайдер с Javascript, используя технику клонирования и перевода. Ниже приведен рабочий пример: -

var fragPre = document.createDocumentFragment(),
    fragPost = document.createDocumentFragment(),
    clonedPre, clonedPost,
    selectSlide = document.getElementById("numberOfSlides"),

    //options
    numberOfSlides = 3;


var items   = document.querySelectorAll("#gallery .slider-scroller-inner .item"),
    len     = items.length,
    current = 1,  /* the current item we're looking */
    wrapper = document.getElementById("wrapper"),
    transformVal = 0;


/* 1. Cloning last items and appending to first */  

for(var i=numberOfSlides ; i > 0 ; i--) {
    clonedPre = items[items.length-i].cloneNode(true);
    fragPre.append(clonedPre);
}

wrapper.insertBefore(fragPre , items[0]);

/* . Cloning first items and appending to first */  

for(var j = 0 ; j <= numberOfSlides-1 ; j++) {
    clonedPost = items[j].cloneNode(true);
    fragPost.append(clonedPost);
}

wrapper.appendChild(fragPost);

/* Slider arrow click function */  

var slideWidth=items[0].offsetWidth;
var counter = 0;
var timer = null;
var timeout = null;
wrapper.style.transform = "translate3d(" + (-slideWidth) * (numberOfSlides) + "px,0,0)";

function arrowClick(dir) {
    clearTimeout(timeout);
    timeout = setTimeout(function() {
        counter = 0;
        direction = dir;
        var str = wrapper.style.transform;
        var left = str.substring(12, str.length - 11);
        console.log(left);
        animateSlide(current, left);
    }, 300);
}

/* slide number click function */  

function changeCurrent(curr) {
    current = curr;
    wrapper.style.transform =  "translate3d(" + -(slideWidth) * (current + (numberOfSlides-1)) + "px,0,0)";
}


/* actual sliding effect */  

function animateSlide(curr, left) {
    var timer = setInterval(function() {
        if(counter < slideWidth) {
            transformVal = parseInt(left, 10) + (-(++counter) * direction);
            wrapper.style.transform = "translate3d(" + transformVal + "px,0,0)";
        } else {
            current += direction;
            cycle = !!(current === 0 || current > len);
            if (cycle) {
              current = (current === 0)? len : 1;
              wrapper.style.transform ="translate3d(" + (-(slideWidth) * (current + (numberOfSlides-1))) + "px,0,0)";
            }
            counter = 0;
            clearInterval(timer);
        }
    }, 0);  
}
  
body {
    margin: 0;
    padding: 0;
}

.carousel-slider-wrapper {
    width: 1200px;
    margin: 0 auto;
    position: relative;
}

.slider-scroller-wrap {
    overflow: hidden;
}

.slider-scroller {
    font-size: 0;
    white-space: nowrap;
    position: relative;
    top: 0;
    margin: 0;
    padding: 0;
}
.slider-scroller-inner {
  /* transition: .2s ease-out; */
  
}
.slider-scroller-inner {
    display: flex;
    width: 100%;
    position: relative;
}

.slider-scroller-inner .item {
    display: inline-block;
    vertical-align: top;
    /* padding: 2px; */
    box-sizing: border-box;
    /* border: 1px solid; */
    cursor: grab;
    text-align: center;
    flex: 0 0 33.33%;
}

.slider-scroller-inner .item img {
    max-width: 100%;
}

button {
    font: 40px "Courier New";
    border: none;
    box-shadow: 1px 2px 3px #666666;
    background: #e4e4e4;
    color: #626262;
    cursor: pointer;
    text-align: center;
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    height: 70px;
    z-index: 1;
}

button.prev {
    left: 0;
}

button.next {
    right: 0;
}

label, a {
    font: 14px Georgia;
    font-style: italic;
    color: #626262;
}

#indicators {
    padding: 0;
    margin: 1rem 0;
    overflow: hidden;
    text-align: center;
}
#indicators li {
    padding: .5rem;
    border-radius: 100%;
    font-weight: bold;
    background: #7592bd;
    display: inline-flex;
    height: 1.4rem;
    width: 1.4rem;
    color: #FFFFFF;
    text-align: center;
    cursor: pointer;
    justify-content: center;
    align-items: center;
    margin-right: .3rem;
}

#indicators li:hover {
    box-shadow: 1px 2px 3px #333333;
}
image Ниже приведены шаги, которые я выполняю: -
  1. Я клонирую последние несколько элементов, добавляю к первым и клонирую первые несколько элементы и добавление его до конца (спасибо посту: - { ссылка }). Просто чтобы иметь бесконечный эффект, когда я нахожусь на первом или последнем предмете.

  2. по щелчку стрелки я трансформирую контейнер предмета с таким же размером, что и размер предмета, учитывая сторону, где я преобразую .

  3. внутри setInterval Я проверяю, является ли его первый элемент или последний и соответственно перемещает мой скользящий контейнер.

Над кодом работает нормально. Просто я сталкиваюсь с проблемами с функцией setIntervals: - 1. Он очень медленно трансформирует слайд.

если я делаю несколько нажатий на стрелку, на слайде происходит странный эффект.

1 Ответ

1 голос
/ 20 января 2020

Вам просто нужно немного лучше управлять timeout

для анимации, гораздо более подходящим является использование css:

transition: all 0.5s; будет хорошо работать.

Я обновил ваш пример

Пояснения в комментариях

var fragPre = document.createDocumentFragment(),
    fragPost = document.createDocumentFragment(),
    clonedPre, clonedPost,
    selectSlide = document.getElementById("numberOfSlides"),

    //options
    numberOfSlides = 3;


var items   = document.querySelectorAll("#gallery .slider-scroller-inner .item"),
    len     = items.length,
    current = 1,  /* the current item we're looking */
    wrapper = document.getElementById("wrapper"),
    transformVal = 0;


/* 1. Cloning last items and appending to first */  

for(var i=numberOfSlides ; i > 0 ; i--) {
    clonedPre = items[items.length-i].cloneNode(true);
    fragPre.append(clonedPre);
}

wrapper.insertBefore(fragPre , items[0]);

/* . Cloning first items and appending to first */  

for(var j = 0 ; j <= numberOfSlides-1 ; j++) {
    clonedPost = items[j].cloneNode(true);
    fragPost.append(clonedPost);
}

wrapper.appendChild(fragPost);

/* Slider arrow click function */  

var slideWidth=items[0].offsetWidth;
var counter = 0;
var timer = null;
var timeout = null;
wrapper.style.transform = "translate3d(" + (-slideWidth) * (numberOfSlides) + "px,0,0)";

function arrowClick(dir) {
    // if timeout || timer is not null than sliding is processing right now, prevent processing user's actions in this case
    if (timeout || timer) {
      return;
    }
    timeout = setTimeout(function() {
        counter = 0;
        direction = dir;
        var str = wrapper.style.transform;
        var left = str.substring(12, str.length - 11);
        console.log(left);
        animateSlide(current, left);
        timeout = null; // <-- setting timeout to null that will mean that function is partly (also will check timer) ready for new user's actions
    }, 300);
}

/* slide number click function */  

function changeCurrent(curr) {
    current = curr;
    wrapper.style.transform =  "translate3d(" + -(slideWidth) * (current + (numberOfSlides-1)) + "px,0,0)";
}


/* actual sliding effect */  

function animateSlide(curr, left) {
    // if timer is not prevent processing new animation
    if (timer) {
      return;
    }
    timer = setInterval(function() {
        if(counter < slideWidth) {
            counter += 2; // <-- this is the speed of animation. bigger number faster animating
            transformVal = parseInt(left, 10) + (-(counter) * direction);
            wrapper.style.transform = "translate3d(" + transformVal + "px,0,0)";
        } else {
            current += direction;
            cycle = !!(current === 0 || current > len);
            if (cycle) {
              current = (current === 0)? len : 1;
              wrapper.style.transform ="translate3d(" + (-(slideWidth) * (current + (numberOfSlides-1))) + "px,0,0)";
            }
            counter = 0;
            clearInterval(timer);
            timer = null; // <-- setting timer to null and now it's ready for another animaton
        }
    }, 0);  
}
body {
    margin: 0;
    padding: 0;
}

.carousel-slider-wrapper {
    width: 1200px;
    margin: 0 auto;
    position: relative;
}

.slider-scroller-wrap {
    overflow: hidden;
}

.slider-scroller {
    font-size: 0;
    white-space: nowrap;
    position: relative;
    top: 0;
    margin: 0;
    padding: 0;
}
.slider-scroller-inner {
  /* transition: .2s ease-out; */
  
}
.slider-scroller-inner {
    display: flex;
    width: 100%;
    position: relative;
}

.slider-scroller-inner .item {
    display: inline-block;
    vertical-align: top;
    /* padding: 2px; */
    box-sizing: border-box;
    /* border: 1px solid; */
    cursor: grab;
    text-align: center;
    flex: 0 0 33.33%;
}

.slider-scroller-inner .item img {
    max-width: 100%;
}

button {
    font: 40px "Courier New";
    border: none;
    box-shadow: 1px 2px 3px #666666;
    background: #e4e4e4;
    color: #626262;
    cursor: pointer;
    text-align: center;
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    height: 70px;
    z-index: 1;
}

button.prev {
    left: 0;
}

button.next {
    right: 0;
}

label, a {
    font: 14px Georgia;
    font-style: italic;
    color: #626262;
}

#indicators {
    padding: 0;
    margin: 1rem 0;
    overflow: hidden;
    text-align: center;
}
#indicators li {
    padding: .5rem;
    border-radius: 100%;
    font-weight: bold;
    background: #7592bd;
    display: inline-flex;
    height: 1.4rem;
    width: 1.4rem;
    color: #FFFFFF;
    text-align: center;
    cursor: pointer;
    justify-content: center;
    align-items: center;
    margin-right: .3rem;
}

#indicators li:hover {
    box-shadow: 1px 2px 3px #333333;
}
image
...