Слайдер в слайдере

Предположим, нужно крутить несколько фотогалерей в слайдере. Например, миниатюры записей из категорий. Таким образом, главный слайдер будет ротировать категории, а тело каждого слайда будет содержать слайдер записей. Чтобы было интереснее, сделаем даже два слайдера записей в каждом слайде категорий. Начнём с макета.

Макет слайдера в слайдере.

Будем использовать Swiper slider. HTML шаблон у него такой:

<div class="swiper">
  <!-- Additional required wrapper -->
  <div class="swiper-wrapper">
    <!-- Slides -->
    <div class="swiper-slide">Slide 1</div>
    <div class="swiper-slide">Slide 2</div>
    <div class="swiper-slide">Slide 3</div>
    ...
  </div>
  <!-- If we need pagination -->
  <div class="swiper-pagination"></div>

  <!-- If we need navigation buttons -->
  <div class="swiper-button-prev"></div>
  <div class="swiper-button-next"></div>

  <!-- If we need scrollbar -->
  <div class="swiper-scrollbar"></div>
</div>

Главный слайдер

Для главного слайдера, согласно макету, пагинация и скроллбар нам не нужны, поэтому упрощаем до:

<div class="swiper">
  <div class="swiper-wrapper">
    <div class="swiper-slide">Slide 1</div>
    <div class="swiper-slide">Slide 2</div>
    <div class="swiper-slide">Slide 3</div>
  </div>
  <div class="swiper-button-prev"></div>
  <div class="swiper-button-next"></div>
</div>

Так как я являюсь одним из лучших специалистов по WordPress, сделаю сразу вывод категорий, чтобы работать с кодом одного слайда в цикле категорий. Так будет нагляднее.

<div class="swiper">
  <div class="swiper-wrapper">
    <?php
    $categories = get_categories();
    if( $categories ){ 
      foreach( $categories as $cat ){ 
        ?>
        <div class="swiper-slide">
          <div class="cat-name"><?= $cat->name ?></div>
          <div class="cat-gallery"></div>
        </div>
        <?php
      }
    }
    ?>
  </div>
  <div class="swiper-button-prev"></div>
  <div class="swiper-button-next"></div>
</div>

Внутренние слайдеры

Добавим их внутрь элементов с классом swiper-slide. Шаблон будет таким же, только у слайдера миниатюр не будет стрелок. Также, чтобы прописать различные стили и поведение для стрелок главного слайдера и внутреннего слайдера фото, добавим к навигации главного слайдера класс parent, а к навигации фото — класс child.

<div class="swiper parent-slider">
  <div class="swiper-wrapper">
    <?php
    $categories = get_categories();
    if( $categories ){ 
      foreach( $categories as $cat ){ 
        ?>
        <div class="swiper-slide">
          <div class="cat-name"><?= $cat->name ?></div>
          <div class="cat-gallery">
            <div class="swiper child-slider-photos">
              <div class="swiper-wrapper">
                <?php
                $photos = get_posts([
                  'category' => $cat->term_id,
                  'exclude' => get_the_ID(),
                ]);
                foreach ($photos as $photo) {
                  ?>
                  <div class="swiper-slide">
                    <a href="<?= get_permalink( $photo->ID ) ?>">
                      <img src="<?= get_the_post_thumbnail_url( $photo->ID, 'large' ); ?>" alt="<?= get_the_title( $photo->ID ) ?>">
                    </a>
                  </div>
                  <?php
                }
                wp_reset_postdata();
                ?>
              </div>
              <div class="swiper-button-prev child"></div>
              <div class="swiper-button-next child"></div>
            </div>
            <div class="swiper child-slider-thumbs">
              <div class="swiper-wrapper">
                <?php
                foreach ($photos as $photo) {
                  ?>
                  <div class="swiper-slide">
                    <img src="<?= get_the_post_thumbnail_url( $photo->ID, 'thumbnails' ); ?>" alt="<?= get_the_title( $photo->ID ) ?>">
                  </div>
                  <?php
                }
                wp_reset_postdata();
                ?>
              </div>
            </div> 
          </div>
        </div>
        <?php
      }
    }
    ?>
  </div>
  <div class="swiper-button-prev parent"></div>
  <div class="swiper-button-next parent"></div>
</div>

Итак, слайдеры — это элементы с классом swiper. Чтобы инициализирующий javascript смог отличить главный слайдер от внутренних и внутренние между собой, добавил различные классы к swiper.

  • parent-slider — для главного;
  • child-slider-photos — для фото;
  • child-slider-thumbs — для миниатюр.

На этом, работа с HTML закончена.

Инициализация нескольких слайдеров на одной странице

Ради этого и пишу. Как сделать несколько слайдеров на одной странице без присвоения каждому уникального идентификатора и соответственного ему JS кода? Будем искать элементы по классу и циклически инициализировать их поочередно.

const parentSlider = new Swiper(".parent-slider", {
  noSwiping: true,
  navigation: {
    nextEl: ".swiper-button-next.parent",
    prevEl: ".swiper-button-prev.parent",
  },
});
const catGalleryItems = document.querySelectorAll(".cat-gallery");
let photos = [];
let thumbs = []; 
catGalleryItems.forEach((catGallery, index) => {
  thumbs[index] = new Swiper(catGallery.querySelector(".child-slider-thumbs"), {
    spaceBetween: 10,
    slidesPerView: 4,
    freeMode: true,
    watchSlidesProgress: true,
  });
  photos[index] = new Swiper(catGallery.querySelector(".child-slider-photos"), {
    lazy: true,
    thumbs: {
      swiper: thumbs[index],
    },
    navigation: {
      nextEl: ".swiper-button-next.child",
      prevEl: ".swiper-button-prev.child",
    },
  });
});

Чтобы разнести навигацию слайдеров подальше друг от друга, добавлю стили:

.parent-slider {
  width: 640px;
}
.child-slider-photos {
  margin: 0 0 10px;
}
.child-slider-thumbs .swiper-slide {
  opacity: 0.4;
}
.child-slider-thumbs .swiper-slide-thumb-active {
  opacity: 1;
}
.cat-name {
  font-size: 36px;
  font-weight: bold;
  color: #000;
  line-height: 50px;
  margin: 0 0 20px;
}
.swiper-button-prev.parent,
.swiper-button-next.parent {
  color: #000;
  top: 23px !important;
}
.swiper-button-prev.parent {
  left: unset !important;
  right: 50px !important;
}
.swiper-button-next.parent {
  right: 0 !important;
}

Вот что получилось.

Frameworks
HTML
JavaScript
Linux
MySQL