将 Prev Next 控件添加到 Carousel

时间:2021-07-05 22:01:21

标签: javascript jquery controls intervals

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

请参阅 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);

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

我是否应该在命名函数中编写相关代码,以便在按下按钮时调用它并传递索引参数? (在这种情况下,我如何处理相同的索引变量?) 按钮叠加的最佳做法是什么?

帮助! 提前致谢

1 个答案:

答案 0 :(得分:1)

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

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

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"
    }
  ]
});

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

<头>
方法 说明
anim() 修复索引如果超过幻灯片或为负值并动画到新索引
prev() 递减索引并触发anim()
next() 增加索引并触发anim()
stop() 清除循环间隔(在鼠标输入时)
play() 开始循环(每 next() 毫秒触发一次 pause

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:或者,如果您的代码跟踪上一个/下一个的方向,也可以编写增加/减少/环回当前索引的逻辑as(前面的伪代码!):

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

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