Swiper JS Pagination

Подскажите пожалуйста, как сделать, что-бы булеты были бесконечны, а активный булет всегда был по центру, как на этой картинке.

А также, можно ли задать, чтобы отображалось конкретное число булетов, например 7, в центре активный и от него по бокам 3.

отображение конкретного числа булетов

Не важно какой слайд по счету идет, активный булет всегда в центре.

slidesPerView: 1,
spaceBetween: 30,
centeredSlides: true,
loop: true,
pagination: {
    el: ".swiper-pagination",
    dynamicBullets: true,
},

На оф. сайте не смог найти информацию.


Ответы (1 шт):

Автор решения: Dev18

Насколько мне известно, параметр dynamicBullets в Swiper делает активный булет крупнее, но не центрирует его.
Также в Swiper нет встроенного режима, который делает "виртуальные" булеты и всегда держит активный по центру, как в примере на вашем изображении.

Чтобы реализовать такой эффект, предложу такой вариант:

  • оставляем значение по умолчанию pagination: false,
  • создаём собственный DOM-блок с булетами,
  • и при каждом переключении слайда обновлять эти булеты вручную так, чтобы активный оставался по центру.
  • это кастомное решение, поэтому при изменении количества слайдов, стоит тестировать

const BULLETS_TO_SHOW = 7;
const BULLETS_SIDE = Math.floor(BULLETS_TO_SHOW / 2);

const swiper = new Swiper('.swiper', {
  slidesPerView: 'auto',
  centeredSlides: true,
  spaceBetween: 30,
  loop: true,
  on: {
    init(swiper) {
      updateBullets(swiper);
    },
    slideChange(swiper) {
      updateBullets(swiper);
    },
  }
});

function updateBullets(swiperInstance) {
  const totalSlides = swiperInstance.slides.length - swiperInstance.loopedSlides * 2;
  const realIndex = swiperInstance.realIndex;
  const container = document.querySelector('.custom-pagination');
  container.innerHTML = '';

  for (let i = -BULLETS_SIDE; i <= BULLETS_SIDE; i++) {
    let bulletIndex = (realIndex + i + totalSlides) % totalSlides;
    const bullet = document.createElement('span');
    bullet.className = 'custom-bullet';
    if (i === 0) bullet.classList.add('active');

    bullet.addEventListener('click', () => {
      swiperInstance.slideToLoop(bulletIndex);
    });

    container.appendChild(bullet);
  }
}
.swiper {
  width: 100%;
  max-width: 700px;
  height: 350px;
  margin: auto;
}

.swiper-slide {
  width: 80%;
  flex-shrink: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}

.swiper-slide img {
  width: 100%;
  height: auto;
  border-radius: 12px;
}

.custom-pagination {
  display: flex;
  justify-content: center;
  gap: 8px;
  margin-top: 20px;
}

.custom-bullet {
  width: 10px;
  height: 10px;
  background: #ccc;
  border-radius: 50%;
  transition: all 0.3s ease;
  cursor: pointer;
}

.custom-bullet.active {
  background: #007aff;
  transform: scale(1.5);
}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css" />


<div class="swiper">
  <div class="swiper-wrapper">
    <div class="swiper-slide"><img src="https://i.sstatic.net/8en8F8TK.png" alt="1"></div>
    <div class="swiper-slide"><img src="https://i.sstatic.net/IxdomiLW.png" alt="2"></div>
    <div class="swiper-slide"><img src="https://i.sstatic.net/2ffgSLzM.png" alt="3"></div>
    <div class="swiper-slide"><img src="https://i.sstatic.net/oTvahlCA.png" alt="4"></div>
    <div class="swiper-slide"><img src="https://i.sstatic.net/yrLQxCB0.png" alt="5"></div>
    <div class="swiper-slide"><img src="https://i.sstatic.net/Lu5xevdr.png" alt="6"></div>
    <div class="swiper-slide"><img src="https://i.sstatic.net/mLdQWkFD.png" alt="7"></div>
  </div>
</div>

<div class="custom-pagination"></div>

<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>

→ Ссылка