如何使用纯 JavaScript 和 CSS 创建垂直轮播

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32080077/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 14:49:21  来源:igfitidea点击:

How to create a vertical carousel using plain JavaScript and CSS

javascripthtmlcssanimationcarousel

提问by Dabbler00

I am trying to create a vertical carousel using vanilla JavaScript and CSS. I know that jQuery has a carousel library but I want to have a go at building this from scratch using no external libraries. I started off by just trying to move the top image and then I planned to move on to making the next image move. I got stuck on the first image. This is where I need your help, StackOverflowers.

我正在尝试使用 vanilla JavaScript 和 CSS 创建一个垂直轮播。我知道 jQuery 有一个 carousel 库,但我想尝试不使用外部库从头开始构建它。我开始只是尝试移动顶部图像,然后我计划继续移动下一个图像。我被困在第一张图片上。这就是我需要你帮助的地方,StackOverflowers。

My HTML:

我的 HTML:

<div class="slider vertical" >
    <img class="first opened" src="http://malsup.github.io/images/beach1.jpg">
    <img class="opened" src="http://malsup.github.io/images/beach2.jpg">
    <img src="http://malsup.github.io/images/beach3.jpg">
    <img src="http://malsup.github.io/images/beach4.jpg">
    <img src="http://malsup.github.io/images/beach5.jpg">
    <img src="http://malsup.github.io/images/beach9.jpg">
</div>
<div class="center">
    <button id="prev">∧ Prev</button>
    <button id="next">∨ Next</button>
</div>

JavaScript:

JavaScript:

var next = document.getElementById('next');
var target = document.querySelector('.first');

next.addEventListener('click', nextImg, false);

function nextImg(){
     if (target.classList.contains('opened')) {
        target.classList.remove('opened');
        target.classList.add('closed');
    } else {
        target.classList.remove('closed');
        target.classList.add('opened');
    }
}

CSS:

CSS:

div.vertical {
    width: 100px;
}

.slider {
    position: relative;
    overflow: hidden;
    height: 250px;

        -webkit-box-sizing:border-box;
       -moz-box-sizing:border-box;
        -ms-box-sizing:border-box;
            box-sizing:border-box;

    -webkit-transition:-webkit-transform 1.3s ease;
       -moz-transition:   -moz-transform 1.3s ease;
        -ms-transition:    -ms-transform 1.3s ease;
            transition:        transform 1.3s ease;
}

.slider img {
    width: 100px;
    height: auto;
    padding: 2px;
}

.first.closed{
    /* partially offscreen */
    -webkit-transform: translate(0, -80%);
       -moz-transform: translate(0, -80%);
        -ms-transform: translate(0, -80%);
            transform: translate(0, -80%);
}

.first.opened{
    /* visible */
    -webkit-transform: translate(0, 0%);
       -moz-transform: translate(0, 0%);
        -ms-transform: translate(0, 0%);
            transform: translate(0, 0%);
}

My mode of thinking was:

我的思维模式是:

  1. use classes to move and show content
  2. use JavaScript to add and remove classes
  1. 使用类移动和显示内容
  2. 使用 JavaScript 添加和删除类

I think I may not have broken the problem down properly.

我想我可能没有正确地分解问题。

This is how I would like it to look: http://jsfiddle.net/natnaydenova/7uXPx/

这就是我想要的样子:http: //jsfiddle.net/natnaydenova/7uXPx/

And this is my abysmal attempt: http://jsfiddle.net/6cb58pkr/

这是我糟糕的尝试:http: //jsfiddle.net/6cb58pkr/

回答by Michael Laszlo

An alternative to using CSS transformproperties is to give the carousel absolute positioning inside a wrapper divand manipulate the carousel's topproperty. Then you can use any easing function you like to animate the sliding motion. In the snippet below, I use cubic easing in/out.

使用 CSStransform属性的另一种方法是在包装器内为轮播提供绝对定位div并操纵轮播的top属性。然后您可以使用任何您喜欢的缓动功能来为滑动动作设置动画。在下面的代码段中,我使用了三次缓入/出

A tricky thing to watch out for is the order in which you rotate the images and perform the sliding animation. When you want to show the next picture below, you have to:

需要注意的一件棘手的事情是旋转图像和执行滑动动画的顺序。当你想显示下面的下一张图片时,你必须:

  • slide the carousel up by the height of one picture frame
  • rotate the first image to the end
  • reset the carousel's vertical offset to zero
  • 将旋转木马向上滑动一个相框的​​高度
  • 将第一张图片旋转到最后
  • 将轮播的垂直偏移重置为零

To show the next picture above:

要显示上面的下一张图片:

  • rotate the last image to the beginning
  • instantly move the carousel up by the height of one picture frame
  • slide the carousel down until its vertical offset reaches zero
  • 将最后一张图片旋转到开头
  • 立即将旋转木马向上移动一个相框的​​高度
  • 向下滑动转盘,直到其垂直偏移量为零

In the following snippet, you can set the width of the carousel by adjusting Carousel.widthat the top of the script. (Although the image height doesn't have to be the same as the image width, I do assume that all images have the same dimensions.) You can also play around with the Carousel.numVisibleand Carousel.durationparameters.

在以下代码段中,您可以通过Carousel.width在脚本顶部进行调整来设置轮播的宽度。(虽然图像高度不必与图像宽度相同,但我确实假设所有图像具有相同的尺寸。)您还可以使用Carousel.numVisibleCarousel.duration参数。

var Carousel = {
  width: 100,     // Images are forced into a width of this many pixels.
  numVisible: 2,  // The number of images visible at once.
  duration: 600,  // Animation duration in milliseconds.
  padding: 2      // Vertical padding around each image, in pixels.
};

function rotateForward() {
  var carousel = Carousel.carousel,
      children = carousel.children,
      firstChild = children[0],
      lastChild = children[children.length - 1];
  carousel.insertBefore(lastChild, firstChild);
}
function rotateBackward() {
  var carousel = Carousel.carousel,
      children = carousel.children,
      firstChild = children[0],
      lastChild = children[children.length - 1];
  carousel.insertBefore(firstChild, lastChild.nextSibling);
}

function animate(begin, end, finalTask) {
  var wrapper = Carousel.wrapper,
      carousel = Carousel.carousel,
      change = end - begin,
      duration = Carousel.duration,
      startTime = Date.now();
  carousel.style.top = begin + 'px';
  var animateInterval = window.setInterval(function () {
    var t = Date.now() - startTime;
    if (t >= duration) {
      window.clearInterval(animateInterval);
      finalTask();
      return;
    }
    t /= (duration / 2);
    var top = begin + (t < 1 ? change / 2 * Math.pow(t, 3) :
                               change / 2 * (Math.pow(t - 2, 3) + 2));
    carousel.style.top = top + 'px';
  }, 1000 / 60);
}

window.onload = function () {
  document.getElementById('spinner').style.display = 'none';
  var carousel = Carousel.carousel = document.getElementById('carousel'),
      images = carousel.getElementsByTagName('img'),
      numImages = images.length,
      imageWidth = Carousel.width,
      aspectRatio = images[0].width / images[0].height,
      imageHeight = imageWidth / aspectRatio,
      padding = Carousel.padding,
      rowHeight = Carousel.rowHeight = imageHeight + 2 * padding;
  carousel.style.width = imageWidth + 'px';
  for (var i = 0; i < numImages; ++i) {
    var image = images[i],
        frame = document.createElement('div');
    frame.className = 'pictureFrame';
    var aspectRatio = image.offsetWidth / image.offsetHeight;
    image.style.width = frame.style.width = imageWidth + 'px';
    image.style.height = imageHeight + 'px';
    image.style.paddingTop = padding + 'px';
    image.style.paddingBottom = padding + 'px';
    frame.style.height = rowHeight + 'px';
    carousel.insertBefore(frame, image);
    frame.appendChild(image);
  }
  Carousel.rowHeight = carousel.getElementsByTagName('div')[0].offsetHeight;
  carousel.style.height = Carousel.numVisible * Carousel.rowHeight + 'px';
  carousel.style.visibility = 'visible';
  var wrapper = Carousel.wrapper = document.createElement('div');
  wrapper.id = 'carouselWrapper';
  wrapper.style.width = carousel.offsetWidth + 'px';
  wrapper.style.height = carousel.offsetHeight + 'px';
  carousel.parentNode.insertBefore(wrapper, carousel);
  wrapper.appendChild(carousel);
  var prevButton = document.getElementById('prev'),
      nextButton = document.getElementById('next');
  prevButton.onclick = function () {
    prevButton.disabled = nextButton.disabled = true;
    rotateForward();
    animate(-Carousel.rowHeight, 0, function () {
      carousel.style.top = '0';
      prevButton.disabled = nextButton.disabled = false;
    });
  };
  nextButton.onclick = function () {
    prevButton.disabled = nextButton.disabled = true;
    animate(0, -Carousel.rowHeight, function () {
      rotateBackward();
      carousel.style.top = '0';
      prevButton.disabled = nextButton.disabled = false;
    });
  };
};
body {
  font-family: sans-serif;
}
.buttons {
  margin: 5px 0;
}
button {
  font-size: 14px;
  display: inline;
  padding: 3px 6px;
  border: 2px solid #ccc;
  background: #fff;
  border-radius: 5px;
  outline: none;
}
button:hover {
  border: 2px solid #888;
  background: #ffe;
  cursor: pointer;
}
#carouselWrapper {
  position: relative;
  overflow: hidden;
}
#carousel {
  position: absolute;
  visibility: hidden;
}
<div id="spinner"> 
  Loading...
</div>

<div id="carousel">
  <img src="http://malsup.github.io/images/beach1.jpg">
  <img src="http://malsup.github.io/images/beach2.jpg">
  <img src="http://malsup.github.io/images/beach3.jpg">
  <img src="http://malsup.github.io/images/beach4.jpg">
  <img src="http://malsup.github.io/images/beach5.jpg">
  <img src="http://malsup.github.io/images/beach9.jpg">
</div>

<div class="buttons">
  <button id="prev">&uarr; Prev</button>
  <button id="next">&darr; Next</button>
</div>