将 Prev Next 控件添加到 Carousel

Add Prev Next Controls to Carousel

在尝试了定时器和间隔之后,我找到了一个令我满意的解决方案。

参见 relevant jsFiddle 或以下代码:

HTML:

<div id="foo">irrelevant content</div>

javascript(与jQuery):

var post_array = [ "abc", "123", "xyz" ];
var class_array = [ "red", "blue", "green" ];

var interval = 2000;
var i = 0;
var max = post_array.length;
var id ="#foo";

$(id).html(post_array[0]);
$(id).removeClass().addClass(class_array[0]);

setInterval( function(){
    ++i;
    $(id).fadeOut("slow", function() {
    $(id).html(post_array[i%max]).fadeIn("slow");
    $(id).removeClass().addClass(class_array[i%max]);
  });
}, interval);

现在我想知道添加两个允许我返回和堡垒的侧箭头的最佳方法是什么。

我是否应该在命名函数中编写相关代码,以便在按下按钮时调用它并传递索引参数? (在那种情况下我如何对同一个索引变量采取行动?) 按钮覆盖的最佳做法是什么?

求助! 提前致谢

  • 轮播应该是模块化的、可重复使用和可扩展的。当需要将另一个 Carousel 添加到您的 DOM.
  • 时,不要复制粘贴 JS 代码
  • 为了创建 PREV / NEXT 按钮,您还需要一种方法来停止间隔:stop
  • 当您将鼠标悬停在旋转木马上时,您需要暂停 自动播放 以防止非常糟糕的用户体验 (UX)
  • 不要使用 jQuery 制作动画。只需将 is-active class 分配给当前索引幻灯片即可制作动画,然后使用 CSS 对 class.
  • 做任何您想做的事
  • 使用变量index(从0开始)来跟踪当前幻灯片索引
  • You Might Not Need jQuery

旨在使用含糖 class 或正确的 prototype 语法创建一个 class 实例 - 可以像这样使用:

const myCarousel = new Carousel({
  target: "#carousel-one",
  slides: [
    {
      title: "This is slide one",
      image: "images/one.jpg"
    },
    {
      title: "This is slide two! Yey.",
      image: "images/two.jpg"
    }
  ]
});

所以基本上,您需要一个具有这些方法的构造函数

Method Description
anim() Fix index if exceeds slides or is negative and animate to new index
prev() Decrement index and trigger anim()
next() Increment index and trigger anim()
stop() Clear loop interval (On mouseenter)
play() Start loop (Triggers next() every pause milliseconds)

class Carousel {
  constructor(options) {

    Object.assign(this, {
      slides: [],
      index: 0,
      pause: 4000, // Pause between slides
      EL: document.querySelector(options.target || "#Carousel"),
      autoplay: true,
    }, options);

    this.total = this.slides.length;
    this.EL_area = this.EL.querySelector(".Carousel-area");
    this.EL_prev = this.EL.querySelector(".Carousel-prev");
    this.EL_next = this.EL.querySelector(".Carousel-next");

    const NewEL = (tag, prop) => Object.assign(document.createElement(tag), prop);

    // Preload images
    this.ELs_items = this.slides.reduce((DF, item) => {
      const EL_slide = NewEL("div", {
        className: "Carousel-slide"
      });
      const EL_image = NewEL("img", {
        className: "Carousel-image",
        src: item.image,
        alt: item.title
      });
      const EL_content = NewEL("div", {
        className: "Carousel-title",
        textContent: item.title
      });
      EL_slide.append(EL_image, EL_content);
      DF.push(EL_slide);
      return DF;
    }, []);
    this.EL_area.append(...this.ELs_items);

    // Events
    this.EL_prev.addEventListener("click", () => this.prev());
    this.EL_next.addEventListener("click", () => this.next());
    this.EL.addEventListener("mouseenter", () => this.stop());
    this.EL.addEventListener("mouseleave", () => this.play());

    // Init
    this.anim();
    this.play();
  }

  // Methods:

  anim() {
    this.index = this.index < 0 ? this.total - 1 : this.index >= this.total ? 0 : this.index;
    this.ELs_items.forEach((EL, i) => EL.classList.toggle("is-active", i === this.index));
  }

  prev() {
    this.index -= 1;
    this.anim();
  }

  next() {
    this.index += 1;
    this.anim();
  }

  stop() {
    clearInterval(this.itv);
  }

  play() {
    if (this.autoplay) this.itv = setInterval(() => this.next(), this.pause);
  }
}


// Use like:
new Carousel({
  target: "#carousel-one",
  slides: [{
      title: "We're part of nature",
      image: "https://picsum.photos/id/10/400/300"
    },
    {
      title: "Remember to read and learn",
      image: "https://picsum.photos/id/24/400/300"
    },
    {
      title: "Up for a coffee?",
      image: "https://picsum.photos/id/30/400/300"
    },
  ]
});
/* CAROUSEL */

.Carousel {
  position: relative;
  height: 300px;
  max-height: 100vh;
}

.Carousel-slide {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  transition: opacity 0.5s; /* DESIRED SLIDE TRANSITIONS */
  opacity: 0;               /* INACTIVE SLIDE*/
}

.Carousel-slide.is-active { /* ACTIVE SLIDE! */
  opacity: 1;
  z-index: 1;
}

.Carousel-prev,
.Carousel-next {
  position: absolute;
  z-index: 2;
  top: 50%;
  transform: translateY(-50%);
  user-select: none; /* Prevent highlight */
}

.Carousel-prev {
  left: 1em;
}
.Carousel-next{
  right: 1em;
}

.Carousel-image {
  position: absolute;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.Carousel-title {
  position: absolute;
  width: 100%;
  height: 100%;
  color: #fff;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 3em;
}
<div class="Carousel" id="carousel-one">
  <div class="Carousel-area"></div>
  <button class="Carousel-prev" type="button" aria-label="Previous slide">&larr;</button>
  <button class="Carousel-next" type="button" aria-label="Next slide">&rarr;</button>
  <div class="Carousel-desc"></div>
</div>

使用上面的代码,您可以在单个页面上拥有无限数量的轮播,因为每个轮播都有不同的 target ID。


PS:或者,如果您的代码跟踪上一个/下一个的方向,increment/decrement/loopback [=58= 的逻辑]current index 也可以写成(前面的伪代码!):

C = (is_next ? ++C : --C) < 0 ? T-1 : C%T;

其中 C 当前 索引,T 总数 个幻灯片,并且 is_next 是一个布尔值,当方向为 Next.

时为 true