最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - This infinite carousel is not working as intended and I have not been able to find the issue thus far - Stack Overf

programmeradmin3浏览0评论

I have a carousel that I'm using to display products. It shows 3 cards at a time on the desktop viewport and it should start with product 1, 2, & 3. Instead, it starts with 5, 6, & 1.

Then as I click on the right button to move it, it will go to product 2 then on another click, instead of going to product 3, it reverts back to the 5, 6, 1 order.

I'm using Shopify's liquid file format. Here is my code:

  const wrapper = document.querySelector(".wrapper");
  const carousel = document.querySelector(".carousel");
  const firstCardWidth = carousel.querySelector(".card").offsetWidth;
  const arrowBtns = document.querySelectorAll(".wrapper i");
  const carouselChildrens = [...carousel.children];
  
  let isDragging = false, isAutoPlay = true, startX, startScrollLeft, timeoutId;
  
  // Get the number of cards that can fit in the carousel at once
  let cardPerView = Math.round(carousel.offsetWidth / firstCardWidth);
  
  // Insert copies of the last few cards to beginning of carousel for infinite scrolling
  carouselChildrens.slice(-cardPerView).reverse().forEach(card => {
    carousel.insertAdjacentHTML("afterbegin", card.outerHTML);
  });
  
  // Insert copies of the first few cards to end of carousel for infinite scrolling
  carouselChildrens.slice(0, cardPerView).forEach(card => {
    carousel.insertAdjacentHTML("beforeend", card.outerHTML);
  });
  
  // Scroll the carousel at appropriate postition to hide first few duplicate cards on Firefox
  carousel.classList.add("no-transition");
  carousel.scrollLeft = carousel.offsetWidth;
  carousel.classList.remove("no-transition");
  
  // Add event listeners for the arrow buttons to scroll the carousel left and right
  arrowBtns.forEach(btn => {
    btn.addEventListener("click", () => {
      carousel.scrollLeft += btn.id == "left" ? -firstCardWidth : firstCardWidth;
    });
  });
  
  const dragStart = (e) => {
    isDragging = true;
    carousel.classList.add("dragging");
    // Records the initial cursor and scroll position of the carousel
    startX = e.pageX;
    startScrollLeft = carousel.scrollLeft;
  }
  
  const dragging = (e) => {
    if (!isDragging) return; // if isDragging is false return from here
    // Updates the scroll position of the carousel based on the cursor movement
    carousel.scrollLeft = startScrollLeft - (e.pageX - startX);
  }
  
  const dragStop = () => {
    isDragging = false;
    carousel.classList.remove("dragging");
  }
  
  const infiniteScroll = () => {
    // If the carousel is at the beginning, scroll to the end
    if (carousel.scrollLeft === 0) {
      carousel.classList.add("no-transition");
      carousel.scrollLeft = carousel.scrollWidth - (2 * carousel.offsetWidth);
      carousel.classList.remove("no-transition");
    }
    // If the carousel is at the end, scroll to the beginning
    else if (Math.ceil(carousel.scrollLeft) === carousel.scrollWidth - carousel.offsetWidth) {
      carousel.classList.add("no-transition");
      carousel.scrollLeft = carousel.offsetWidth;
      carousel.classList.remove("no-transition");
    }
  
    // Clear existing timeout & start autoplay if mouse is not hovering over carousel
    clearTimeout(timeoutId);
    if (!wrapper.matches(":hover")) autoPlay();
  }
  
  const autoPlay = () => {
    if (window.innerWidth < 800 || !isAutoPlay) return; // Return if window is smaller than 800 or isAutoPlay is false
    // Autoplay the carousel after every 2500 ms
    timeoutId = setTimeout(() => carousel.scrollLeft += firstCardWidth, 2500);
  }
  autoPlay();
  
  carousel.addEventListener("mousedown", dragStart);
  carousel.addEventListener("mousemove", dragging);
  document.addEventListener("mouseup", dragStop);
  carousel.addEventListener("scroll", infiniteScroll);
  wrapper.addEventListener("mouseenter", () => clearTimeout(timeoutId));
  wrapper.addEventListener("mouseleave", autoPlay);
#shopify-section-template--16302064730196__product_slider_epcazc {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100%;
}

.product-slider__wrapper-container {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100%;
}

.wrapper {
  display: flex;
  justify-content: center;
  align-items: center;
  max-width: 1100px;
  width: 100%;
  position: relative;
}

.wrapper i {
  font-size: 4rem;
  font-weight: 300;
  color: #fff;
  top: 50%;
  height: 50px;
  width: 50px;
  cursor: pointer;
  position: relative;
  text-align: center;
  line-height: 50px;
  transform: translateY(-50%);
  transition: transform 0.1s linear;
}

.wrapper i:active {
  transform: translateY(-50%) scale(0.85);
}

.wrapper i:first-child {
  padding-right: 20px;
}

.wrapper i:last-child {
  padding-left: 20px;
}

.carousel {
  scroll-behavior: smooth;
}

.wrapper .carousel {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: calc((100% / 3) - 12px);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  gap: 16px;
  border-radius: 8px;
  scroll-behavior: smooth;
  scrollbar-width: none;
  padding: 0;
  justify-content: center;
}

.carousel::-webkit-scrollbar {
  display: none;
}

.carousel.no-transition {
  scroll-behavior: auto;
}

.carousel.dragging {
  scroll-snap-type: none;
  scroll-behavior: auto;
}

.carousel.dragging .card {
  cursor: grab;
  user-select: none;
}

.carousel :where(.card, .img) {
  display: flex;
  justify-content: center;
  align-items: center;
}

.carousel .card {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  overflow: hidden;
  scroll-snap-align: start;
  height: 360px;
  list-style: none;
  background: #fff;
  cursor: pointer;
  flex-direction: column;
  border-radius: 8px;
}

.carousel .card .img {
  height: 70%;
  width: 100%;
}

.card .img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.product-slider__details-container {
  background: #000;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: center;
  width: 100%;
  height: 30%;
}

.product-slider__title {
  color: #fff;
  font-family: 'Genos', serif;
  font-weight: 500;
  font-size: 1.7rem;
  padding: 1.5rem 1rem;
  text-align: center;
  margin: 0;
}

.product-slider__price {
  color: #fff;
  font-family: 'Genos', serif;
  font-weight: 500;
  font-size: 1.55rem;
  padding-bottom: 1rem;
  margin: 0;
}

.carousel .card span {
  color: #6A6D78;
  font-size: 1.31rem;
}

@media screen and (max-width: 900px) {
  .wrapper .carousel {
      grid-auto-columns: calc((100% / 2) - 9px);
  }
}

@media screen and (max-width: 600px) {
  .wrapper .carousel {
      grid-auto-columns: 100%;
  }

  .carousel .card {
      height: auto;
      max-height: 350px;
  }
}

.best-sellers-container {
  padding: 0 15px;
  background-color: #111111;
  width: 100%;
}

.best-sellers {
  background-image: url(.jpg?v=1738795837);
  background-repeat: no-repeat;
  background-size: cover;
  background-position: 50% 50%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  position: relative;
  border-top-left-radius: 25px;
  border-top-right-radius: 25px;
  overflow: hidden;
  padding: 3rem 0;
}

.bg-overlay {
  display: block;
  position: absolute;
  width: 100%;
  height: 100%;
  background-color: rgba(0,0,0,0.3);
  top: 0;
}

.best-sellers-title-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  position: relative;
  z-index: 10;
}

.best-sellers-title-container h2 {
  color: #fff;
  font-family: 'Genos', serif;
  font-size: calc(var(--font-heading-scale) * 7rem);
  text-transform: uppercase;
  text-align: center;
  line-height: 1.2;
  font-weight: 500;
  position: relative;
  bottom: 15px;
  letter-spacing: -2px;
  margin: 0;
}

@media only screen and (max-width: 750px) {
  .best-sellers-container {
    padding: 0 10px;
  }
  
  .best-sellers-title-container h2 {
    font-size: calc(var(--font-heading-scale) * 4.5rem);
    margin-top: 0;
    bottom: 10px;
  }
}

.best-sellers-title-container p {
  color: #fff;
  font-family: 'Montserrat', serif;
  font-size: 1.5rem;
  text-align: center;
  letter-spacing: 0;
  margin-top: 0;
  max-width: 600px;
}

.best-sellers__grid-item {
  border-radius: 3px;
  overflow: hidden;
}
<div class="best-sellers-container">
  <div class="best-sellers"
    id="collection-template--16302064730196__featured_collection_d6PVfW"
    data-id="template--16302064730196__featured_collection_d6PVfW">
    <div class="bg-overlay"></div>
    <div
      class="best-sellers-title-container">
      <h4 class="sub-title-heading">Check out our</h4>
      <h2 class="title inline-richtext h1 scroll-trigger animate--slide-in">
        Best Sellers
      </h2>
      <p>From timeless classics to the latest trends, these hand-picked selections have consistently received high
        praise. Explore our curated collection of top-rated items and find your next favorite today.</p>
    </div>

    <div class="product-slider__wrapper-container">
      <div class="wrapper">
        <i id="left" class="fa-solid fa-angle-left"></i>
        <ul class="carousel">
          {% assign best_products = collections['best-sellers'].products | sort_natural: 'title' %}
          <li class="card">
            <div class="img">
              <img src="{{ best_products[0].featured_media | image_url: width: 533 }}" alt="img" draggable="false"
                width="" height="">
            </div>
            <div class="product-slider__details-container">
              <h2 class="product-slider__title">{{ best_products[0].title }}</h2>
              <h2 class="product-slider__price">{{ best_products[0].price | money }}</h2>
            </div>
          </li>
          <li class="card">
            <div class="img">
              <img src="{{ best_products[1].featured_media | image_url: width: 533 }}" alt="img" draggable="false"
                width="" height="">
            </div>
            <div class="product-slider__details-container">
              <h2 class="product-slider__title">{{ best_products[1].title }}</h2>
              <h2 class="product-slider__price">{{ best_products[1].price | money }}</h2>
            </div>
          </li>
          <li class="card">
            <div class="img">
              <img src="{{ best_products[2].featured_media | image_url: width: 533 }}" alt="img" draggable="false"
                width="" height="">
            </div>
            <div class="product-slider__details-container">
              <h2 class="product-slider__title">{{ best_products[2].title }}</h2>
              <h2 class="product-slider__price">{{ best_products[2].price | money }}</h2>
            </div>
          </li>
          <li class="card">
            <div class="img">
              <img src="{{ best_products[3].featured_media | image_url: width: 533 }}" alt="img" draggable="false"
                width="" height="">
            </div>
            <div class="product-slider__details-container">
              <h2 class="product-slider__title">{{ best_products[3].title }}</h2>
              <h2 class="product-slider__price">{{ best_products[3].price | money }}</h2>
            </div>
          </li>
          <li class="card">
            <div class="img">
              <img src="{{ best_products[4].featured_media | image_url: width: 533 }}" alt="img" draggable="false"
                width="" height="">
            </div>
            <div class="product-slider__details-container">
              <h2 class="product-slider__title">{{ best_products[4].title }}</h2>
              <h2 class="product-slider__price">{{ best_products[4].price | money }}</h2>
            </div>
          </li>
          <li class="card">
            <div class="img">
              <img src="{{ best_products[5].featured_media | image_url: width: 533 }}" alt="img" draggable="false"
                width="" height="">
            </div>
            <div class="product-slider__details-container">
              <h2 class="product-slider__title">{{ best_products[5].title }}</h2>
              <h2 class="product-slider__price">{{ best_products[5].price | money }}</h2>
            </div>
          </li>
        </ul>
        <i id="right" class="fa-solid fa-angle-right"></i>
      </div>
    </div>
  </div>
</div>
发布评论

评论列表(0)

  1. 暂无评论