JS Slider with Stacked Slider for Navigation

Viewed 203

I'm looking to build out a slider that auto cycles through individual slides, but also has a navigation that is stacked, and also a slider. Like this: enter image description here

The main issues I am running into are having that synced slider only show 1 "active" slide, and the navigation being stacked, and in it's own slider. As it auto plays through to "7" the slider on the bottom should slide over to show that one is active. This is the closest I could hack together:

My code:

$('.slider-for').slick({
  autoplay: true,
  autoplaySpeed: 1000,
  speed: 700,
  mobileFirst: true,
  slidesToScroll: 1,
  slidesToShow: 1,
  rows: 1,
  fade: true,
  swipeToSlide: true,
  infinite: false,
  focusOnSelect: true,
  pauseOnHover: false,
  arrows: false,
  dots: false,
  asNavFor: '.slider-nav'
});

$('.slider-nav').slick({
  autoplay: false,
  autoplaySpeed: 9000,
  speed: 700,
  mobileFirst: true,
  slidesToScroll: 1,
  slidesToShow: 2,
  rows: 3,
  swipeToSlide: true,
  infinite: false,
  focusOnSelect: true,
  pauseOnHover: false,
  arrows: true,
  dots: true,
  asNavFor: '.slider-for'
});

$('.slick').slick();

var $parent = $(".slider-for");
var $nav = $(".slider-nav");
var $content = $nav.find("div");
var killit = false;

$content.on("click", function(e) {
  if (!killit) {
    e.stopPropagation();
    var idx = $(this).data("thumb");
    $parent.slick("goTo", idx - 1);
  }
});

$nav.on("beforeChange", function() {
  killit = true;
}).on("afterChange", function() {
  killit = false;
});
body {
  background: gray;
}

.slider {
  font-family: Arial;
  width: 500px;
  display: block;
  margin: 0 auto;
}

.slider h3 {
  background: #fff;
  color: #3498db;
  font-size: 36px;
  line-height: 100px;
  margin: 10px;
  padding: 2%;
  position: relative;
  text-align: center;
}

.slider .action {
  display: block;
  margin: 100px auto;
  width: 100%;
  text-align: center;
}

.slider .action a {
  display: inline-block;
  padding: 5px 10px;
  background: #f30;
  color: #fff;
  text-decoration: none;
}

.slider .action a:hover {
  background: #000;
}

.slick-active {
  border: 1px solid red
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<script src="https://kenwheeler.github.io/slick/slick/slick.js"></script>

<link rel="stylesheet" type="text/css" href="https://kenwheeler.github.io/slick/slick/slick.css"/>

<link rel="stylesheet" type="text/css" href="https://kenwheeler.github.io/slick/slick/slick-theme.css"/>

<div class="slider">
  <div class="slider-for">
    <div>
      <h3>1</h3>
    </div>
    <div>
      <h3>2</h3>
    </div>
    <div>
      <h3>3</h3>
    </div>
    <div>
      <h3>4</h3>
    </div>
    <div>
      <h3>5</h3>
    </div>
    <div>
      <h3>6</h3>
    </div>
    <div>
      <h3>7</h3>
    </div>
    <div>
      <h3>8</h3>
    </div>
    <div>
      <h3>9</h3>
    </div>
    <div>
      <h3>10</h3>
    </div>
    <div>
      <h3>11</h3>
    </div>
    <div>
      <h3>12</h3>
    </div>
  </div>
  <div class="slider-nav">
    <div data-thumb="1">
      <h3>1</h3>
    </div>
    <div data-thumb="2">
      <h3>2</h3>
    </div>
    <div data-thumb="3">
      <h3>3</h3>
    </div>
    <div data-thumb="4">
      <h3>4</h3>
    </div>
    <div data-thumb="5">
      <h3>5</h3>
    </div>
    <div data-thumb="6">
      <h3>6</h3>
    </div>
    <div data-thumb="7">
      <h3>7</h3>
    </div>
    <div data-thumb="8">
      <h3>8</h3>
    </div>
    <div data-thumb="9">
      <h3>9</h3>
    </div>
    <div data-thumb="10">
      <h3>10</h3>
    </div>
    <div data-thumb="11">
      <h3>11</h3>
    </div>
    <div data-thumb="12">
      <h3>12</h3>
    </div>
  </div>
</div>

View on jsFiddle

1 Answers

The asNavFor property works perfectly if both sliders have the same row property. But because you want the second slider to have three rows you have to use an own sync-function.


First you have to prepare the children of .slider-for: Give them data-thumb attributes like the children of .slider-nav have.

After that you can get the index of the shown slide of .slider-for with that data-thumb attribute

let for_index = $(this).find('.slick-current')[0].dataset.thumb;

and calculate with it the slide index for .slider-nav. Here you have to subtract 1 from for_index because it starts with 1 instead of 0 (like an index would do).

let nav_index = Math.floor((for_index - 1) / 3);

Then you goTo that index.

$('.slider-nav').slick('goTo', nav_index);

To get it to work you have to wrap all that in an event listener (and its handler). I used the setPosition event for that because it styles the current slide on init.


Working example: (simplified for demonstration)

I changed the red border to a brighter background because the border messed up the slider, even with box-sizing: border-box (the last slide was moved to a second, hidden row and therefor not visible).

I also removed autoplaySpeed and speed for .slider-nav because autoplay and fade are set to false.

$('.slider-for').slick({
  autoplay: true,
  autoplaySpeed: 1000,
  mobileFirst: true,
  slidesToScroll: 1,
  slidesToShow: 1,
  rows: 1,
  fade: true,
  speed: 700,
  swipeToSlide: true,
  infinite: false,
  focusOnSelect: true,
  pauseOnHover: false,
  arrows: false,
  dots: false
});

$('.slider-nav').slick({
  autoplay: false,
  mobileFirst: true,
  slidesToScroll: 1,
  slidesToShow: 2,
  rows: 3,
  swipeToSlide: true,
  infinite: false,
  focusOnSelect: true,
  pauseOnHover: false,
  arrows: true,
  dots: true
});

$('.slider-for').on('setPosition', function() {
  let for_index = $(this).find('.slick-current')[0].dataset.thumb;
  let nav_index = Math.floor((for_index - 1) / 3);
  
  $('.slider-nav').slick('goTo', nav_index);
  $('.slider-nav .slick-slide').css('background-color', 'transparent');
  $('.slider-nav .slick-slide[data-slick-index="' + nav_index + '"]').css('background-color', '#aaa');
});
body {
  background: gray;
}

.slider {
  font-family: Arial;
  width: 500px;
  display: block;
  margin: 0 auto;
}

.slider h3 {
  background: #fff;
  color: #3498db;
  font-size: 36px;
  line-height: 100px;
  margin: 10px;
  padding: 2%;
  text-align: center;
  transition-delay: 0s;
}

.slider .slick-dots li button::before {
  font-size: 15px;
  color: white;
}

.slider .slick-dots li.slick-active button::before {
  color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<script src="https://kenwheeler.github.io/slick/slick/slick.js"></script>

<link rel="stylesheet" type="text/css" href="https://kenwheeler.github.io/slick/slick/slick.css"/>

<link rel="stylesheet" type="text/css" href="https://kenwheeler.github.io/slick/slick/slick-theme.css"/>

<div class="slider">

  <div class="slider-for">
    <div data-thumb="1">
      <h3>1</h3>
    </div>
    <div data-thumb="2">
      <h3>2</h3>
    </div>
    <div data-thumb="3">
      <h3>3</h3>
    </div>
    <div data-thumb="4">
      <h3>4</h3>
    </div>
    <div data-thumb="5">
      <h3>5</h3>
    </div>
    <div data-thumb="6">
      <h3>6</h3>
    </div>
    <div data-thumb="7">
      <h3>7</h3>
    </div>
    <div data-thumb="8">
      <h3>8</h3>
    </div>
    <div data-thumb="9">
      <h3>9</h3>
    </div>
    <div data-thumb="10">
      <h3>10</h3>
    </div>
    <div data-thumb="11">
      <h3>11</h3>
    </div>
    <div data-thumb="12">
      <h3>12</h3>
    </div>
  </div>

  <div class="slider-nav">
    <div data-thumb="1">
      <h3>1</h3>
    </div>
    <div data-thumb="2">
      <h3>2</h3>
    </div>
    <div data-thumb="3">
      <h3>3</h3>
    </div>
    <div data-thumb="4">
      <h3>4</h3>
    </div>
    <div data-thumb="5">
      <h3>5</h3>
    </div>
    <div data-thumb="6">
      <h3>6</h3>
    </div>
    <div data-thumb="7">
      <h3>7</h3>
    </div>
    <div data-thumb="8">
      <h3>8</h3>
    </div>
    <div data-thumb="9">
      <h3>9</h3>
    </div>
    <div data-thumb="10">
      <h3>10</h3>
    </div>
    <div data-thumb="11">
      <h3>11</h3>
    </div>
    <div data-thumb="12">
      <h3>12</h3>
    </div>

</div>

Related