【问题标题】:Trying to make continuous JavaScript slider尝试制作连续的 JavaScript 滑块
【发布时间】:2017-06-29 16:04:39
【问题描述】:

我的滑块的问题是,当它到达最后一张幻灯片并单击下一步时,它会跳过两张幻灯片以到达第一张。同样,当我在第一张幻灯片上并单击上一张时,它会跳过幻灯片以到达最后一张。我想当我到达最后一张幻灯片并单击NEXT 时,第一张幻灯片将从右到左出现。 (与第一张幻灯片上的PREVIOUS 按钮类似)。我尝试使用insertBefore()appendChild() 制作幻灯片,但无法弄清楚...

这是我的代码:

// Slider
const slider_wrapp = document.querySelector('.tract-slider');
const slider = document.querySelector('.tract-slider-wrapp');
var slide = document.getElementsByClassName('tract-slide');

const leftBtn = document.querySelector('.slide-left');
const rightBtn = document.querySelector('.slide-right');

let swWidth = slider_wrapp.clientWidth;
let sliderWidth = swWidth * slide.length;
let slideWidth = 0;

slider.style.width = sliderWidth + "px";

for (var i = 0; i < slide.length; i++) {
  slide.item(i).style.width = swWidth + "px";
}

function moveRight() {
  slideWidth === sliderWidth - swWidth ? slideWidth = 0 : slideWidth += swWidth;
  slider.style.transform = "translateX(" + (-slideWidth) + "px)";

}

function moveLeft() {
  slideWidth === 0 ? slideWidth = sliderWidth - swWidth : slideWidth -= swWidth;
  slider.style.transform = "translateX(" + (-slideWidth) + "px)";
}

rightBtn.addEventListener("click", function() {
  moveRight();
});

leftBtn.addEventListener("click", function() {
  moveLeft();
});
.tract-slider {
  width: 100%;
  height: 75vh;
  position: relative;
  overflow: hidden;
}

.tract-slider-wrapp {
  height: 100%;
  position: relative;
  -webkit-transition: all 350ms cubic-bezier(.08, .13, 0, .81);
  -o-transition: all 350ms cubic-bezier(.08, .13, 0, .81);
  transition: all 350ms cubic-bezier(.08, .13, 0, .81);
}

.tract-slide {
  height: 100%;
  float: left;
  position: relative;
  display: block;
  background-position: center;
  -webkit-background-size: cover;
  background-size: cover;
}

.tract-slide:nth-child(1) {
  background-image: url("https://static.pexels.com/photos/126282/pexels-photo-126282.jpeg");
}

.tract-slide:nth-child(2) {
  background-image: url("https://static.pexels.com/photos/29017/pexels-photo-29017.jpg");
}

.tract-slide:nth-child(3) {
  background-image: url("https://static.pexels.com/photos/70760/dandelion-dandelion-seeds-taraxacum-fluffy-70760.jpeg");
}

.tract-slider-control {
  position: absolute;
  left: 0;
  bottom: 0;
  background: #ffffff;
  padding: 1em;
}

.tract-slider-btn {
  display: inline-block;
  cursor: pointer;
  margin-left: 1em;
}

.tract-slider-btn:nth-child(1) {
  margin-left: 0;
}
<div class="tract-slider">
  <div class="tract-slider-wrapp">
    <div class="tract-slide"></div>
    <div class="tract-slide"></div>
    <div class="tract-slide"></div>
  </div>
  <div class="tract-slider-control">
    <div class="tract-slider-btn slide-left">Prev</div>
    <div class="tract-slider-btn slide-right">Next</div>
  </div>
</div>

附言。请使用 JavaScript 解决方案

【问题讨论】:

    标签: javascript html css slider


    【解决方案1】:

    创建无限滑块意味着您需要在 DOM 中移动幻灯片,以便它们给人以连续轨道的印象。

    您需要更改的第一件事是让它们的背景与它们在 DOM 中的位置相关联。如果我们想从第一张幻灯片滑回最后一张,我们需要取最后一张幻灯片,在第一张之前添加它,但是,考虑到您当前的 CSS,这将改变所有幻灯片的背景,因为它们目前绑定到他们在 DOM 中的位置 (...:nth-child {background-image:...}...)。

    需要改变的第二件事是将幻灯片定位到滑块轨道中。如果它们是浮动的,那么每当我们更改它们的顺序时,所有其余的幻灯片都会受到影响。通过使用position:absolute 定位它们,每张幻灯片独立移动,而不会影响其他幻灯片,因此在保持控制的同时更容易重新排列它们。

    长话短说,我从头开始,将所有方法放在一个对象中:theSlider

    reset() 函数完成了繁重的工作:它将 before 类放在第一个元素上,current 在第二个元素上,after 在所有其余元素上。所以你必须把“最后一个”幻灯片放在第一位,因为滑块会在“当前”之前添加它。

    通过将go-leftgo-right 类应用于轨道来完成滑动。转换完成后,我只是将第一张/最后一张幻灯片移动到新位置,具体取决于大小写,然后再次运行 reset()(它会剥离所有类并根据新位置重新应用它们)。
    动画由 CSS 处理。 JavaScript 所做的只是应用/删除类并在 DOM 中移动幻灯片。

    var theSlider = {
      track : document.querySelector('.tract-slider-wrapp'),
      // has to match `transition-duration` in CSS:
      duration : 600,
      reset : function() {
        var slides = document.querySelectorAll('.tract-slider-wrapp > div');
        for (var i = 0; i < slides.length; i++) {
          slides[i].className = '';
          slides[i].classList.add(i > 1? 'after' : (i ? 'current':'before'))
        }
      },
      init : function() {
        theSlider.reset();
        theSlider.track.classList.remove('not-loaded')
      },
      next : function() {
        theSlider.track.classList.add('go-right');
        setTimeout(function(){
          var firstSlide = document.querySelector('.tract-slider-wrapp > div:first-child');
          theSlider.track.appendChild(firstSlide);
          theSlider.reset();
          theSlider.track.classList.remove('go-right')
        },theSlider.duration)
      },
      prev : function() {
        theSlider.track.classList.add('go-left');
        setTimeout(function() {
          var lastSlide = document.querySelector('.tract-slider-wrapp > div:last-child');
          theSlider.track.insertBefore(lastSlide, theSlider.track.firstChild);
          theSlider.reset();
          theSlider.track.classList.remove('go-left')
        },theSlider.duration)
      },
      prevButton : document.querySelector('.slide-left'),
      nextButton : document.querySelector('.slide-right')
    };
    window.addEventListener("load", theSlider.init);
    theSlider.prevButton.addEventListener('click', theSlider.prev);
    theSlider.nextButton.addEventListener('click', theSlider.next);
    .tract-slider {
      width: 100%;
      height: 75vh;
      position: relative;
      overflow: hidden;
      background-color: #f5f5f5;
    }
    
    .tract-slider-wrapp {
      height: 100%;
      transition: all 350ms cubic-bezier(.08, .13, 0, .81);
      opacity: 1;
    }
    .tract-slider-wrapp.not-loaded {
      opacity: 0;
    }
    
    .tract-slider-wrapp>div {
      height: 100%;
      position: absolute;
      background: transparent no-repeat 50% 50% /cover;
      width: 100%;
    }
    .tract-slider-wrapp > div.before {
      margin-left: -100%;
    }
    .tract-slider-wrapp > div.current + div {
      margin-left: 100%;
    }
    .tract-slider-wrapp > div.after ~ div {
      opacity: 0;
    }
    .tract-slider-control {
        position: absolute;
        width: 100%;
        z-index: 1;
        top: 50%;
        display: flex;
        justify-content: space-between;
        transform: translateY(-50%);
    }
    .tract-slider-control div {
      background-color: rgba(0,0,0,.35);
      padding: .5rem 1rem;
      color: white;
      cursor: pointer;
    }
    .tract-slider-control :first-child {
      border-radius: 0 17px 17px 0;
    }
    .tract-slider-control :last-child { 
      border-radius: 17px 0 0 17px;
    }
    body {
      margin: 0;
    }
    .go-right div {
      transform: translateX(-100%);
    }
    .go-left div {
      transform: translateX(100%);
    }
    .go-right div, .go-left div {
      transition-property: transform;
      transition-timing-function: cubic-bezier(.4,0,.2,1);
      /* has to match `duration` in js: */
      transition-duration: 600ms;
    }
    <div class="tract-slider">
      <div class="tract-slider-wrapp not-loaded">
        <div style="background-image:url('https://static.pexels.com/photos/126282/pexels-photo-126282.jpeg')"></div>
        <div style="background-image:url('https://static.pexels.com/photos/29017/pexels-photo-29017.jpg')"></div>
        <div style="background-image:url('https://static.pexels.com/photos/70760/dandelion-dandelion-seeds-taraxacum-fluffy-70760.jpeg')"></div>
      </div>
      <div class="tract-slider-control">
        <div class="tract-slider-btn slide-left">Prev</div>
        <div class="tract-slider-btn slide-right">Next</div>
      </div>
    </div>

    如果要更改动画时长,则需要在 js 和 css 中进行更改。
    目前唯一的限制是它需要至少 3 张幻灯片才能工作。我想它可以通过以下方式调整为仅使用两张幻灯片:将“非活动”幻灯片克隆到第三个位置,在转换后删除克隆并克隆另一张。


    待办事项:

    • 为 CSS 添加前缀,使其适用于更多浏览器
    • 如果你想向 IE 表达爱意,请将.classList.add('whatever') 替换为.className += ' whatever'
      .classList.remove('whatever').className.replace('whatever', '')

    我上面说的只是为了告诉你:如果你想继续前进,不要重新发明轮子。

    您使用香草 javascript 真是太好了。但迟早你会为常见的东西编写自己的包装器。根据你的能力/已经变得多好,你将编写自己的、有限的、自定义的 jQuery 版本。请允许我把事情放在透视图上:谷歌在 AngularJS 中包含了一个精简版的 jQuery。真是太好了。

    作为一名开发人员,您没有机会编写出更好、更精简和经过测试的版本。此外,您不必这样做。用你的技能和能力向前走,而不是横着走。

    【讨论】:

    • 你好,再次,我有一个小问题,当我向幻灯片添加一些内容(文本等)并移动幻灯片时,它会随着幻灯片移动,然后返回到我定位的位置它是。 (绝对,在这种情况下,左侧为 0,底部为 0),我认为这是因为该边距但无法弄清楚,我知道解决方案是用另一个宽度为 100% 的 div 包裹它;高度 100%;但也许有更好的解决方案......这是小提琴:jsfiddle.net/650gcj37/5
    • @user8227676,它与最初的问题关系不大。虽然我可以在这里回答,但它会使未来遇到类似问题的用户无法从可索引的答案中受益。请提出一个单独的问题,我会提供帮助。
    猜你喜欢
    • 1970-01-01
    • 2013-04-27
    • 2018-12-06
    • 2015-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多