Como criar um carrossel vertical usando JavaScript e CSS simples

Estou a tentar criar um carrossel vertical usando vanilla JavaScript e CSS. Sei que o jQuery tem uma biblioteca de carrossel, mas quero tentar construir isto do zero, sem bibliotecas externas. Eu comecei apenas tentando mover a imagem de cima e então eu planejei seguir em frente para fazer o próximo movimento da imagem. Fiquei preso na primeira imagem. É aqui que preciso da tua ajuda, StackOverflowers.

A Minha 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:

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:

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%);
}
O meu modo de pensar foi:
  1. usar as classes para mover e mostrar o conteúdo
  2. usar JavaScript para adicionar e remover classes
Acho que não quebrei o problema correctamente.

É assim que eu gostaria que parecesse: http://jsfiddle.net/natnaydenova/7uXPx/

E esta é a minha tentativa abismal. http://jsfiddle.net/6cb58pkr/

Author: Michael Laszlo, 2015-08-18

1 answers

Uma alternativa à utilização das propriedades CSS transform é dar ao carrossel um posicionamento absoluto dentro de uma embalagem div e manipular a propriedade do carrossel top. Então você pode usar qualquer função de suavização que você gosta para animar o movimento de deslizamento. No excerto abaixo, eu uso cúbico de entrada / saída .

Uma coisa complicada a ter em atenção é a ordem pela qual você roda as imagens e executa a animação deslizante. Quando você quer mostrar a próxima imagem abaixo, você tem to:

  • desliza o carrossel pela altura de uma moldura
  • roda a primeira imagem até ao fim
  • repõe a posição vertical do carrossel a zero

Para mostrar a imagem seguinte acima:

  • roda a última imagem para o início
  • mova instantaneamente o carrossel pela altura de uma moldura
  • deslize o carrossel para baixo até que a sua posição vertical atinja zero

No seguinte trecho, você pode definir a largura do carrossel ajustando Carousel.width no topo do script. (Embora a altura da imagem não tenha que ser a mesma que a largura da imagem, eu assumo que todas as imagens têm as mesmas dimensões.) Você também pode brincar com os parâmetros Carousel.numVisible e Carousel.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>
 8
Author: Michael Laszlo, 2015-08-19 01:15:41