スライダーといえばSwiper!

スライダーといえばSwiper!

いまだによく出会うスライダー実装

僕がWEB業界に入ってから6年ほど経ちますが、当時からいまだにメインビジュアルに使いがちなスライダー。 制作者側はUIどうなの?とか賛否ありますが、クライアントからの要望で付けることはまだまだ全然あります。

そんな出くわすことの多いスライド実装ですが、そこに時間かけてられないのでちゃちゃっと実装しちゃいたいですよね。

そんな時にオススメなのが「Swiper」というプラグイン。

Swiper

https://idangero.us/swiper/

スライドのプラグインをGoogleで探すといろんなプラグインが出てきますが、Swiperが紹介されている記事がけっこうあるので、知ってる人や実際使っている人もかなり多いんじゃないでしょうか?

僕はもうかれこれ5年くらいはこのプラグインを使っているんじゃないかな?というぐらいスライド実装があればこちらをまず選択します。

読み込んですぐに使えるだけでなく、APIが豊富でカスタマイズ性がとても高くて重宝しています。

では実際に使い方を見ていきましょう!

Swiperを使う準備

まずはyarnでインストール

$ yarn add -D swiper

yarnの公式サイトはこちら。

Yarn

https://yarnpkg.com/ja/

もっと簡単にCDNで試す方はこちら。

<!-- 通常版 -->
<link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.css">
<!-- 圧縮版 -->
<link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.min.css">

<!-- 通常版 -->
<script src="https://unpkg.com/swiper/swiper-bundle.js"></script>
<!-- 圧縮版 -->
<script src="https://unpkg.com/swiper/swiper-bundle.min.js"></script>

読み込むのはCSSとJSです。圧縮版と通常版がありますので好きな方を読み込みます。

4.x.xはバージョンです。お好みのバージョンを指定してください。この記事を執筆時の最新バージョンは4.5.0でしたので今回はそれを使います。
5.0系になったので対応しました。
6.0系になったので一部書き直しました。デモはv6.0.4を使用しています。
バージョン6.0への対応は下記の記事が参考になります。

swiper ver.6.0.x へのバージョンアップに対応する

https://qiita.com/TAO_TAO_/items/9c679b37d1f9375d74ca

2021.11.16
v7へのアップグレード対応についての記事を書きました。

IE11対応が必要な場合は4.0系を使いましょう。4.0系の最新は4.5.1となっています。4.0系を使う場合は、読み込むJSファイルとCSSファイルが最新のものと違っているので注意です。

<!-- 4.0系通常版 -->
<link rel="stylesheet" href="https://unpkg.com/swiper@4.5.1/dist/css/swiper.css">
<!-- 4.0系圧縮版 -->
<link rel="stylesheet" href="https://unpkg.com/swiper@4.5.1/dist/css/swiper.min.css">

<!-- 4.0系通常版 -->
<script src="https://unpkg.com/swiper@4.5.1/dist/js/swiper.js"></script>
<!-- 4.0系圧縮版 -->
<script src="https://unpkg.com/swiper@4.5.1/dist/js/swiper.min.js"></script>

yarnでローカルにインストールした場合でもCSSは必要なので環境に合わせて適宜読み込んでおきます。

これでSwiperを使う準備ができました。

Swiperの基本実装

実際にhtmlとJSを書いていきます。
ここではとりあえずごく基本的なスライダーを作ってみます。

HTML

<body>
  <div class="swiper-container">
    <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-pagination"></div>

    <!-- 前へ/次へ -->
    <div class="swiper-button-prev"></div>
    <div class="swiper-button-next"></div>

  </div>
</body>

htmlのポイントは、swiper-xxxxとなっているclassが付いている要素です。
swiper-containerswiper-wrapperswiper-slideは必須で、この構造にしないとうまく動かないので注意です。
ページネーションやナビゲーション(前へ/次へボタン)に関してはデフォルト以外のclassを指定することも可能です。ただ個人的にはそのままを使ってあとからCSSを上書きする方が楽です。

JS

<script>
  var mySwiper = new Swiper ('.swiper-container', {
    loop: true,
    pagination: {
      el: '.swiper-pagination',
    },
    navigation: {
      nextEl: '.swiper-button-next',
      prevEl: '.swiper-button-prev',
    }
  })
</script>

JSはこれだけ。本当に説明が要らないくらいシンプル。
一応ここで使うプロパティだけ説明しておくと

  • loop:スライドを無限ループさせるか。true / false
  • pagenation.el:ページネーションを表示させる要素を指定。
  • navigation.nextEl:次へボタンの要素を指定
  • navigation.prevEl:前へボタンの要素を指定

これで基本的なスライダーはできました。
DEMO - Swiper基本

これ以外にも基本的な実装は公式のデモが1番わかりやすいです!

Swiper DEMO

https://idangero.us/swiper/demos/

これだけでもうすぐにでも使えますね!
オプションがかなり豊富なので、公式サイトを見ながら自分なりにカスタマイズできるのがさらにオススメしたいポイントです!

Swiper API

https://idangero.us/swiper/api/



Swiperの使い方 - 応用編 -

ここまでで充分通常の案件に使えると思いますが、ちょっと応用してみます。
クライアントの要望でよく遭遇するのが「サムネイル付きのスライダーにしたい」というものです。これは公式のデモにあるのですが、さらによくあるカスタマイズが「スマホではサムネイルをスライドに、PCではサムネイルを全て表示したい」というような画面サイズやデバイズに合わせた挙動の変更を依頼されることがあります。

実際にこれをデモで実装してみます。
完成したものはこちら。

DEMO - 応用編

Swiper - 応用編の実装

詳細を見ていきます。
デモ用なので画像は入れずにあくまで動きのみの実装になります。

HTML

<body>
  <div class="cover">
    <div class="frame">
      <div class="swiper-container slide" id="slide">
        <div class="swiper-wrapper">
          <div class="swiper-slide">
            <p>1</p>
          </div>
          <div class="swiper-slide">
            <p>2</p>
          </div>
          <div class="swiper-slide">
            <p>3</p>
          </div>
          ・
          ・
          ・
          <div class="swiper-slide">
            <p>20</p>
          </div>
          <!-- swiper-slideを20個用意する -->
        </div>
        <!-- /.swiper-wrapper -->
        <!-- 前へ/次へ -->
        <div class="swiper-button-prev"></div>
        <div class="swiper-button-next"></div>
      </div>
      <!-- /.swiper-container -->
      <div class="swiper-container thumbnail" id="thumbnail">
        <div class="swiper-wrapper">
          <div class="swiper-slide">
            <p>1</p>
          </div>
          <div class="swiper-slide">
            <p>2</p>
          </div>
          <div class="swiper-slide">
            <p>3</p>
          </div>
          ・
          ・
          ・
          <div class="swiper-slide">
            <p>20</p>
          </div>
          <!-- 同じくswiper-slideを20個用意する -->
        </div>
        <!-- /.swiper-wrapper -->
      </div>
      <!-- /.swiper-container -->
    </div>
    <!-- /.frame -->
  </div>
  <!-- /.cover -->
</body>

ポイントはメインになるスライドと、サムネイル用のスライドを全く同じ順番でつくること。サムネイルの方は小さめの画像を置いてあげると多少は負荷軽減になると思います。

CSS

.cover{
  padding: 30px;
}

.frame{
  max-width: 1080px;
  margin: auto;
}

.slide{
  margin-bottom: 10px;
  border: 1px solid #ccc;
}

.slide .swiper-slide {
  width: 100%;
  height: 300px;
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
  -webkit-align-items: center;
  -ms-flex-align: center;
  align-items: center;
  -webkit-box-pack: center;
  -webkit-justify-content: center;
  -ms-flex-pack: center;
  justify-content: center;
  font-size: 60px;
  font-weight: 900;
}

.thumbnail .swiper-slide{
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
  -webkit-align-items: center;
  -ms-flex-align: center;
  align-items: center;
  -webkit-box-pack: center;
  -webkit-justify-content: center;
  -ms-flex-pack: center;
  justify-content: center;
  padding: 15px;
  font-size: 18px;
  font-weight: 900;
  border: 1px solid #ccc;
}

.thumbnail .swiper-slide::before{
  pointer-events: none;
  opacity: 0;
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  z-index: 10;
  display: block;
  width: 100%;
  height: 100%;
  border: 6px solid #007aff;
  transition: .3s ease;
}

.thumbnail .swiper-slide-thumb-active::before{
  opacity: 1;
}

@media screen and (min-width: 768px) {
  .thumbnail .swiper-wrapper{
    -webkit-flex-wrap:wrap;
    -ms-flex-wrap:wrap;
    flex-wrap:wrap;
  }
  .thumbnail .swiper-slide{
    width: 9.1%;
    height: 60px;
    padding: 30px 0;
    margin-right:1%;
    margin-bottom: 1%;
    font-size: 24px;
  }
  .thumbnail .swiper-slide:nth-child(10n){
    margin-right: 0;
  }
}

CSSはメインのスライドの下にサムネイルがぴったりはまるように調整。
今回は画像も載せていないのであくまで体裁を整えるだけにしました。

JS

続いてここが今回の応用のポイントになるJavaScript。
よく批判の的になる大好きなjQueryを一部使って書いていきます。

<script>
  //メインスライド
  var mainSlideOption = {
    loop           : true,
    navigation     : {
      nextEl : '.swiper-button-next',
      prevEl : '.swiper-button-prev',
    }
  }
  var mainSlide = new Swiper('#slide', mainSlideOption);

  //サムネイルスライド
  var thumbnailOption = {
    loop                  : true,
    spaceBetween          : 10,
    slidesPerView         : 6,
    slideToClickedSlide   : true,
    centeredSlides        : true
  };
  var thumbnail = new Swiper('#thumbnail', thumbnailOption);

  //サムネイルをクリックした時のイベント
  $(document).on('click', '#thumbnail .swiper-slide', (e) => {
    if(thumbnail){
      mainSlide.slideToLoop(thumbnail.realIndex);
    }
    else{
      var index = $('#thumbnail .swiper-slide').index(e.currentTarget);
      mainSlide.slideToLoop(index);
    }
  });

  //メインスライドが動いた時のイベント
  mainSlide.on('slideChange', () => {
    if($(window).innerWidth() < 768){
      thumbnail.slideToLoop(mainSlide.realIndex);
    }
    else {
      $('#thumbnail .swiper-slide').removeClass('is-active');
      $('#thumbnail .swiper-slide').eq(mainSlide.realIndex).addClass('is-active');
    }
  });

  var resizeTimer = null;
  var resizeFlag  = true;
  //リサイズイベント
  $(window).on('load resize', () => {
    if(resizeFlag){
      resizeFlag = false;
      if(resizeTimer){
        window.cancelAnimationFrame(resizeTimer);
      }
      resizeTimer = window.requestAnimationFrame(() => {
        if($(window).innerWidth() >= 768){
          if(thumbnail){
            thumbnail.destroy();
            thumbnail = null;
            $('#thumbnail .swiper-wrapper').removeAttr('style');
            $('#thumbnail .swiper-slide').removeAttr('style');
            $('#thumbnail .swiper-slide').eq(mainSlide.realIndex).addClass('is-active');
          }
        }
        else {
          $('#thumbnail .swiper-slide').removeClass('is-active');
          if(!thumbnail){
            thumbnail = new Swiper('#thumbnail', thumbnailOption);
          }
        }
        resizeFlag = true;
      });
    }
  });

</script>

ちょっと長くなりましたので、ポイントを抑えながら見ていきます。

2つのスライドにSwiperを適用する

//メインスライド
var mainSlideOption = {
  loop           : true,
  navigation     : {
    nextEl : '.swiper-button-next',
    prevEl : '.swiper-button-prev',
  }
}
var mainSlide = new Swiper('#slide', mainSlideOption);

//サムネイルスライド
var thumbnailOption = {
  loop                  : true,
  spaceBetween          : 10,
  slidesPerView         : 6,
  slideToClickedSlide   : true,
  centeredSlides        : true
};
var thumbnail = new Swiper('#thumbnail', thumbnailOption);

まずはじめにSwiperを各スライド要素に適用します。
メインスライドはループとナビゲーションボタンを付けただけのシンプルなものに。サムネイルスライドは同じくループあり・6枚表示にしてセンター表示に設定しておきます。

サムネイルをクリックした時にメインスライドを連動させる

2つのスライドができましたが、今はまだ連動性はなく別々に動くスライドです。連動させましょう。

//サムネイルをクリックした時のイベント
$(document).on('click', '#thumbnail .swiper-slide', (e) => {
  if(thumbnail){
    mainSlide.slideToLoop(thumbnail.realIndex);
  }
  else{
    var index = $('#thumbnail .swiper-slide').index(e.currentTarget);
    mainSlide.slideToLoop(index);
  }
});

まず、SwiperのAPIに.slideToLoopという引数に指定したスライドにスライドさせるメソッドがあるのでこれを使います。似たようなメソッドで.slideToがありますが、こちらは今回のようにループを設定しているスライドでは扱いにくいので.slideToloopを使いましょう。

.slideToloopの引数に渡すのは同じくSwiperのAPIにあるプロパティのrealIndexを使います。realIndexには現在activeになっているスライドの番号が入っています。サムネイルスライドのrealIndexを使ってメインスライドを.slideToLoopで動かします。

mainSlide.slideToLoop(thumbnail.realIndex);

これでサムネイルをクリックした時に両方のスライドがactiveになって連動するようになります。

if文で変数thumbnailがある時とそうでない時になっていますが、今回はレスポンシブでPCの時はSwiperを削除するので、削除した時は当然realIndexというSwiper独自のプロパティも削除されます。その場合はjQueryの.indexメソッドを使って要素の順番を渡してあげます。

var index = $('#thumbnail .swiper-slide').index(e.currentTarget);
mainSlide.slideToLoop(index);

これでまず1つめの連動ができました。

メインスライドが動いた時にサムネイルを連動させる

次は逆にメインスライドをナビゲーションやスワイプで動かした時にサムネイルのactiveをさせる処理を書いていきます。

//メインスライドが動いた時のイベント
mainSlide.on('slideChange', () => {
  if($(window).innerWidth() < 768){
    thumbnail.slideToLoop(mainSlide.realIndex);
  }
  else {
    $('#thumbnail .swiper-slide').removeClass('is-active');
    $('#thumbnail .swiper-slide').eq(mainSlide.realIndex).addClass('is-active');
  }
});

ここではSwiperのAPIでslideChangeイベントを使っていきます。
このイベントは現在アクティブなスライドが変更されたときに発生します。つまりスライドが変わった時ですね。このタイミングでさっきと逆にメインスライドのrealIndexプロパティを使ってサムネイルスライドのslideToLoopに適用してやればOKです。

thumbnail.slideToLoop(mainSlide.realIndex);

そしてこちらも同じくレスポンシブでサムネイルスライドが削除されるので、削除された後のスライド要素はrealIndexプロパティが使えないのでjQueryでclassの付け替えをします。

$('#thumbnail .swiper-slide').removeClass('is-active');
$('#thumbnail .swiper-slide').eq(mainSlide.realIndex).addClass('is-active');

追加したis-activeクラスにcssを当ててやればOKです。

これでメインスライド側でactiveになったスライドがサムネイルに連動するようになりました。

レスポンシブでサムネイルのスライドあり・なしを切り替え

ここが本題のところです。

var resizeTimer = null;
var resizeFlag  = true;
//リサイズイベント
$(window).on('load resize', () => {
  if(resizeFlag){
    resizeFlag = false;
    if(resizeTimer){
      window.cancelAnimationFrame(resizeTimer);
    }
    resizeTimer = window.requestAnimationFrame(() => {
      if($(window).innerWidth() >= 768){
        if(thumbnail){
          thumbnail.destroy();
          thumbnail = null;
          $('#thumbnail .swiper-wrapper').removeAttr('style');
          $('#thumbnail .swiper-slide').removeAttr('style');
          $('#thumbnail .swiper-slide').eq(mainSlide.realIndex).addClass('is-active');
        }
      }
      else {
        $('#thumbnail .swiper-slide').removeClass('is-active');
        if(!thumbnail){
          thumbnail = new Swiper('#thumbnail', thumbnailOption);
        }
      }
      resizeFlag = true;
    });
  }
});

細かく見ていきましょう。

まずはjQueryでリサイズイベントを追加します。

var resizeTimer = null;
var resizeFlag  = true;
//リサイズイベント
$(window).on('load resize', () => {
  if(resizeFlag){
    resizeFlag = false;
    if(resizeTimer){
      window.cancelAnimationFrame(resizeTimer);
    }
    resizeTimer = window.requestAnimationFrame(() => {

   //ここにリサイズした時の処理を書く

    resizeFlag = true;
    });
  }
});

リサイズイベントはそのまま使うと思っている以上に連続で発生しまくってバグが出やすいのでrequestAnimationFrameを使って最適化しておきます。(requestAnimationFrameに対応していないブラウザの場合はsetTimeoutで代用できますが、ここでは省略します)

あとはリサイズのタイミングでサムネイルスライドにSwiperを適用したり、削除したりする処理を書いていきます。

//ウィンドウサイズ768px以上の場合
if($(window).innerWidth() >= 768){
  //サムネイルスライドが有れば削除
  if(thumbnail){
    thumbnail.destroy();
    thumbnail = null;
    $('#thumbnail .swiper-wrapper').removeAttr('style');
    $('#thumbnail .swiper-slide').removeAttr('style');
    //activeなサムネイルにクラスを付与
    $('#thumbnail .swiper-slide').eq(mainSlide.realIndex).addClass('is-active');
  }
}
else {
  //ウィンドウサイズ768px未満の場合
  //Swiperを再適用する場合はこちらで付けたis-activeクラスは削除しておく
  $('#thumbnail .swiper-slide').removeClass('is-active');
  if(!thumbnail){
    thumbnail = new Swiper('#thumbnail', thumbnailOption);
  }
}

ここでのポイントは、SwiperのAPIにある.destroyというメソッド。
.destroyを実行するとSwiperインスタンスは削除されますが、各要素についたstyle要素は削除されずに残ってしまうのでjQueryの.removeAttrを使ってSwiperによって追加されたstyle属性を削除しておきます。

さらに「メインスライドが動いた時にサムネイルを連動させる」部分で書いたクラスを付与する処理は、今回は768px以上の場合だけ適用させるのでそれぞれにis-activeクラスの追加・削除処理を書いておきます。

DEMO - 応用編 -

DEMO - 応用編

これで少し複雑な要望にも対応できますね!

【追記】Swiperのオプションだけでサムネイル連動スライドを実装する

応用編では条件がややこしいこともあり、けっこう追加のコードを書かないといけませんでしたが、単にサムネイル連動スライドにするだけならちゃんと公式で用意されている実装方法があります

Swiper API | Thumbs

https://swiperjs.com/api/#thumbs

この方法でサムネイル連動のスライドを実装したデモがこちら。
Swiper - サムネイル連動スライドのデモ

簡単なのでついでに実装方法を載せておきます。

HTML(php)

メインスライドと、連動させるサムネイルスライドを用意します。
画像のソースを書くのがめんどくさかったのでphpでループで回しています。

<body>
  <div class="cover">
    <div class="frame">
      <div class="swiper-container slide" id="js-slide">
        <div class="swiper-wrapper">
          <?php
          $slide_num = 10;
          for ($i = 1; $i <= $slide_num; $i++) {
            ?>
            <div class="swiper-slide">
              <img src="<?php echo esc_url(get_theme_file_uri("include/demo/images/swiper-${i}.jpg"))?>">
            </div>
            <?php
          }
          ?>
        </div>
        <!-- /.swiper-wrapper -->
        <!-- 前へ/次へ -->
        <div class="swiper-button-prev"></div>
        <div class="swiper-button-next"></div>
      </div>
      <!-- /.swiper-container -->
      <div class="swiper-container thumbnail" id="js-thumbs">
        <div class="swiper-wrapper">
          <?php
          for ($i = 1; $i <= $slide_num; $i++) {
            ?>
            <div class="swiper-slide">
              <img src="<?php echo esc_url(get_theme_file_uri("include/demo/images/swiper-thm-${i}.jpg"))?>">
            </div>
            <?php
          }
          ?>
        </div>
        <!-- /.swiper-wrapper -->
      </div>
      <!-- /.swiper-container -->
    </div>
    <!-- /.frame -->
  </div>
  <!-- /.cover -->
</body>

CSS

基本はSwiperのCSSのみで大丈夫ですが、多少の微調整が必要だったのでそれを追記します。<style>タグに追記していますがもちろん外部ファイルにしても大丈夫です。

<link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.min.css">
<style type="text/css">
  img{
    max-width: 100%;
    height: auto;
  }

  .frame{
    max-width: 1080px;
    margin: auto;
  }

  .slide .swiper-slide {
    width: 100%;
  }

  .slide img{
    width: 100%;
    height: 480px;
    object-fit: cover;
    font-family: 'object-fit: cover;';
  }

  .thumbnail .swiper-slide{
    width: 20%;
  }

  .thumbnail .swiper-slide::before{
    pointer-events: none;
    opacity: 0;
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    z-index: 10;
    display: block;
    width: 100%;
    height: 100%;
    border: 6px solid #007aff;
    transition: .3s ease;
  }

  .thumbnail .swiper-slide-thumb-active::before{
    opacity: 1;
  }

  .thumbnail img{
    width: 100%;
    height: 60px;
    object-fit: cover;
    font-family: 'object-fit: cover;';
  }

  @media screen and (min-width: 768px) {
    .cover{
      padding: 30px;
    }

    .slide img{
      height: auto;
    }

    .thumbnail img{
      height: 90px;
      cursor: pointer;
    }
  }

</style>

object-fitを使ったのでIE対応する場合はpolyfillを読み込んでください。

<script src="https://cdnjs.cloudflare.com/ajax/libs/object-fit-images/3.2.3/ofi.js" crossorigin></script>

SCSS

SCSSを使っている場合はver6.0からCSSのインポート先が変わっています。

@import 'swiper/swiper-bundle.min.css';

少し脱線しますが、2022年ごろにSassの@importが廃止予定で@use、@forwardに置き換えた方がいいみたいなことをちょこちょこ聞くようになったので、あまりよくない書き方になってしまいますが現状ではまだ僕自身FLOCSSでCSS設計していて@importから逃れられないのでとりあえずこのままでいきます。

JS

今回はCDNを使わず、ES6+で書きます。
デモはwebpack + Babelでバンドル&トランスパイルしています。

import Swiper from 'swiper/bundle'

class Slide {
  constructor(){
    this.applySwiper();

    $(window).on('load', () => {
      this.objectFitImages();
    });
  }

  //css object-fit polyfill
  objectFitImages() {
    if (typeof objectFitImages != 'undefined') {
      objectFitImages('img');
    }
  }

  //Swiperを適用
  applySwiper(){
    const thumbSlide = this.addThumbSlide();
    this.addMainSlide(thumbSlide);
  }

  /*
  * メインスライド追加
  * @param {Object} thumbSlide サムネイルスライドのSwiperインスタンス
  * @return {Object} メインスライドのSwiperインスタンス
  */
  addMainSlide(thumbSlide){
    const $mainSlide = document.getElementById('js-slide');
    if(!$mainSlide){
      return;
    }
    const param = {
      loop           : true,
      loopedSlides   : 5,
      slidesPerView  : 1,
      spaceBetween   : 0,
      navigation     : {
        nextEl : '.swiper-button-next',
        prevEl : '.swiper-button-prev'
      },
      thumbs         : {
        swiper : thumbSlide
      }
    };
    this.mainSlide = new Swiper('#js-slide', param);
    //2つのスライドの初期表示位置を合わせる
    thumbSlide.slideToLoop(this.mainSlide.realIndex);
    return this.mainSlide;
  }

}

new Slide();

ポイントは5点です。

1、サムネイルスライドにslidesPerViewを設定する

slidesPerViewを必ず設定します。

//サムネイルスライド追加
addThumbSlide(){
  const $thumbSlide = document.getElementById('js-thumbs');
  if(!$thumbSlide){
    return;
  }
  this.thumbSlide = new Swiper('#js-thumbs', {
    loop                  : true,
    centeredSlides        : true,
    slidesPerView         : 5, //必須
    slideToClickedSlide   : true
  });
  return  this.thumbSlide;
}

2、先にサムネイルにSwiperを適用する

サムネイルのSwiperインスタンスをメインスライドのオプションに設定するため、先にサムネイルにSwiperを設定します。

//Swiperを適用
applySwiper(){
  const thumbSlide = this.addThumbSlide();
  this.addMainSlide(thumbSlide);
}

3、メインスライドにThumbオプションを設定する

メインスライドのオプションthumbs.swiperにサムネイルのSwiperインスタンスを設定します。

const param = {
  loop           : true,
  loopedSlides   : 5, //必須
  navigation     : {
    nextEl : '.swiper-button-next',
    prevEl : '.swiper-button-prev'
  },
  watchSlidesVisibility : true,
  watchSlidesProgress   : true,
  thumbs         : {
    swiper : thumbSlide
  }
};

4、メインスライドにloopedSlidesを設定する

loop:true;の場合、表示するサムネイルの数をloopedSlidesに設定します。
10枚中5枚をサムネイル表示させ、あとは自動でページ送りしていくように作ったので5を設定しています。

const param = {
  loop           : true, //ループさせる場合
  loopedSlides   : 5, //これが必須
  navigation     : {
    nextEl : '.swiper-button-next',
    prevEl : '.swiper-button-prev'
  },
  watchSlidesVisibility : true,
  watchSlidesProgress   : true,
  thumbs         : {
    swiper : thumbSlide
  }
};

loop:false;の場合はloopedSlidesは必要ありません。

5、メインスライドとサムネイルの初期表示位置を合わせる

this.mainSlide = new Swiper('#js-slide', param);
//2つのスライドの初期表示位置を合わせる
thumbSlide.slideToLoop(this.mainSlide.realIndex);
return this.mainSlide;

slideToLoopメソッドを使ってメインスライドの初期表示位置をサムネイルスライドに適用します。 realIndexプロパティはloop:true;の場合にスライドの順番を取得できます。
loop:false;の場合はslideToメソッドとactiveIndexプロパティで同じことができると思います。

最初はこちらの処理なしで動かしていたんですが、サムネイルが連動して動いてくれない場合がありましたので付け加えました。

これで完了です!

Swiperのオプションだけで作ったサムネイル連動スライドのDEMO

実際に作ったDEMOはこちら。

Swiper - サムネイル連動スライドのデモ

応用編と主旨が違うのですが、サムネイル付きのスライドを簡単に設置したいだけならこちらで充分ですね!

今回はサムネイルもメインスライドも無限ループするように作りましたが、loop:true;とメインスライドのloopedSlidesを外せばループしないものもできます。

まとめ

今回はスライダーのプラグインSwiperとその使い方についてメモしました。
応用編はちょっと面倒臭い処理にはなりますが、たまに要望としてあるので頭の片隅にでもおいておくと出くわしたときにすぐ対応できるので良いかと思います。

本当にAPIが豊富で他にもいろいろと応用できることがあると思うので、また今後Swiperを使ったちょっと複雑な案件があれば第2弾で紹介したいと思います!