ブレイクポイントでSwiperの作成/解除を行う

ブレイクポイントでSwiperの作成/解除を行う

最近は脱jQueryのため、slickではなく、Swiperを使うこともあります。

まだ数回しか使ったことないですが、色々オプションもあって、理解すれば応用が効くな!という印象です。

慣れの問題でしょうが、まだslickのほうがやりたいことをすぐできていて、Swiperだと大変なこともありますが、これから頑張って使っていきます。


ここから本題ですが、今回やったことを言葉で表すのは難しかったので、とりあえず、次のcodepenで挙動を確認してください。

右上の「EDIT ON CODEPEN」をクリックして、別タブで開いて、width 800pxを境にどう変わるかを見てください。
※当サイトではコンテンツエリアが800px以上にはならないです。

See the Pen swiper responsive by takblog (@blanks-site) on CodePen.

800px以上では、3×2 で写真が表示されて
800px以下ではスライダーになっていることが確認できたと思います。

今回はこのやり方を紹介していきます。

ここで使っているswiperのバージョンは4.5.0です。
swiperのバージョンによってはオプションの書き方が違うので、注意してください。

また書いてあるjavascriptの記述はそのまま使うとIE11では動かない可能性があるので、IE11に対応させるときにはコンパイルツールなどでコンパイルさせてから使ってください。

私が使っているコンパイルツールは以下の記事で紹介しています。

失敗例

最初にやって上手くいかなかったやり方をここでは紹介していきます。

最初に書いたのは以下のような記述です。

const swiperSlides = document.getElementsByClassName('swiper-slide');
const breakPoint = 800;
let mySwiperBool ;

const mySwiper = new Swiper('.swiper-container', {
  init: false,
  speed: 1500,
  autoplay: {
    delay: 2000
  },
  slideToClickedSlide: true,
  spaceBetween: 10,
  slidesPerView: 'auto',
  loop: true,
  loopedSlides: swiperSlides.length,
  centeredSlides: true
});

window.addEventListener('load',()=>{
  if( breakPoint < window.innerWidth ){
    mySwiperBool = false;
  }else if( breakPoint >= window.innerWidth ){
    mySwiper.init();
    mySwiperBool = true;
  }
},false);

window.addEventListener('resize',()=>{
  if( breakPoint < window.innerWidth && mySwiperBool){
    mySwiper.destroy(false,true);
    mySwiperBool = false;
  }else if( breakPoint >= window.innerWidth && !(mySwiperBool)){
    mySwiper.init();
    mySwiperBool = true;
  }
},false);

これで上手くいかなったのは、複数回ブレイクポイントをまたいだ時です。

700px → 900px(swiperは解除される) → 700px(再びswiperが動く) → 900px(swiperが解除されない!)

という感じになったのです。

上記のような書き方では、mySwiper.destory が一度しか動きませんでした。

そこで考えたのは mySwiper が最初にしか定義されていないのが問題なのではないか??ということでした。

二度目以降は destory するmySwiper と、実際に動いている mySwiper は別のものではないか??という予測をして、次の成功例のコードになりました。

成功例

コードをクリップボードにコピー
const swiperSlides = document.getElementsByClassName('swiper-slide');
const breakPoint = 800;
let mySwiper ;
let mySwiperBool ;


window.addEventListener('load',()=>{
  if( breakPoint < window.innerWidth){
    mySwiperBool = false;
  }else{
    createSwiper();
    mySwiperBool = true;
  }
},false);

window.addEventListener('resize',()=>{
  if( breakPoint < window.innerWidth && mySwiperBool){
    mySwiper.destroy(false,true);
    mySwiperBool = false;
  }else if( breakPoint >= window.innerWidth && !(mySwiperBool)){
    createSwiper();
    mySwiperBool = true;
  }
},false);

const createSwiper = () =>{
  mySwiper = new Swiper('.swiper-container', {
    speed: 1500,
    autoplay: {
      delay: 2000
    },
    slideToClickedSlide: true,
    spaceBetween: 10,
    slidesPerView: 'auto',
    loop: true,
    loopedSlides: swiperSlides.length,
    centeredSlides: true
  });
}

失敗例を活かして、ブレイクポイントをまたいで、Swiper を 稼働させる時にmySwiper.init() ではなく、mySwiper = new Swiper(~~) で Swiper を稼働させました。

すると、ちゃんと毎回、mySwiper.destory が動いてくれました!

ちなみに、今回の場合はswiper.cssは以下のようにメディアクエリをつけて読み込んで、801px以上ではswiper.cssが効かないようにしています。

<link rel="stylesheet" href="swiper.css" media="screen and (max-width:800px)">

さらに発展させた例

ここからは、これまでの書き方をさらに発展させます。

.swiper-slideの個数によっては、ブレイクポイント以上でもswiperを動かすような仕様にします。

今回説明するのは以下のような仕様です。

  • 800px 以下ではスライダー。このときスライドの幅は固定幅。(1)
  • 801px以上 かつ、スライド(.swiper-slide)の個数が3個以下のときは、単純に横並び。
  • 801px以上 かつ、スライド(.swiper-slide)の個数が4個以上のときは、(1) と同じスライダーにする。

CMSで組み込む時などでは使いそうな仕様かなと思います。

よくECサイトとかのキービジュアルの下にあるキャンペーンバナーのようなものを想定しています。

html,css,javascriptの例を見ながら、説明しています。

html

コードをポップアップで見る

<!DOCTYPE html>
<html lang="jp">
<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="swiper.css" media="screen and (max-width:800px)" data-style="swiper">
</head>
<body>
  <div id="swiper-outer">
    <div class="swiper-container">
      <div class="swiper-wrapper">
        <div class="swiper-slide"><img src=""></div>
        <div class="swiper-slide"><img src=""></div>
        <div class="swiper-slide"><img src=""></div>
        <div class="swiper-slide"><img src=""></div>
        <div class="swiper-slide"><img src=""></div>
        <div class="swiper-slide"><img src=""></div>
      </div>
    </div>
  </div>
</body>
</html>

htmlの中で重要なのは、2箇所です。

  1. 5行目 swiper.css読み込みのlinkタグにある data-style="swiper" の設定
  2. 8行目 .swiper-containerを囲む要素 #swiper-outerを用意する。

以上の2点はjavascriptでそれぞれを操作したり、cssで #swiper-outer に付いているクラスによってstyleの適用を分けていたりするので重要です。

css

コードをポップアップで見る

@media screen and (min-width: 801px){
  /* swiperが動いてないとき */
  #swiper-outer.noSwiper .swiper-wrapper {
    display: flex;
    justify-content: center;
  }
  #swiper-outer.noSwiper .swiper-slide{
    flex: 0 0 32%;
    max-width: 32%;
    margin-right: 2%;
  }
  #swiper-outer.noSwiper .swiper-slide:last-child{
    margin-right: 0;
  }

  /* swiperが動いているとき */
  #swiper-outer.hasSwiper .swiper-slide{
    width: 320px;
  }
}

@media screen and (max-width: 800px) {
  #swiper-outer .swiper-slide {
    width: 320px;
  }
}

cssでは801px以上のときには、swiperが稼働している場合、稼働していない場合で、cssを分けているのが確認できると思います。

javascript

コードをポップアップで見る

コードをクリップボードにコピー
const swiperOuter = document.getElementById('swiper-outer');            // .swiper-containerを囲む要素
const swiperSlides = document.getElementsByClassName('swiper-slide');   // .swiper-slide要素
const breakPoint = 800;   // ブレイクポイント
const slidesLimit = 4;    // ブレイクポイント以上でもswiperを動作させる .swiper-slide の個数
const initSwiperSlidesLength = swiperSlides.length;     // .swiper-slideの個数
let mySwiper ;
let mySwiperBool ;

window.addEventListener('load',()=>{
  if( initSwiperSlidesLength < slidesLimit ){
    swiperOuter.classList.add('noSwiper');
    if( breakPoint < window.innerWidth){
      mySwiperBool = false;
    }else{
      createSwiper();
      mySwiperBool = true;
    }
    resizeSwiper();
  }else{
    swiperOuter.classList.add('hasSwiper');
    const linktags = document.getElementsByTagName('link');
    for( let i in linktags ){
      if( linktags[i].dataset.style == 'swiper' ){
        linktags[i].setAttribute('media','all');
        break;
      }
    }
    createSwiper();
  }
},false);

const resizeSwiper = () =>{
  window.addEventListener('resize',()=>{
    if( breakPoint < window.innerWidth && mySwiperBool){
      mySwiper.destroy(false,true);
      mySwiperBool = false;
    }else if( breakPoint >= window.innerWidth && !(mySwiperBool)){
      createSwiper();
      mySwiperBool = true;
    }
  },false);
}

const createSwiper = () =>{
  mySwiper = new Swiper('.swiper-container', {
    speed: 1500,
    autoplay: {
      delay: 2000
    },
    slideToClickedSlide: true,
    spaceBetween: 10,
    slidesPerView: 'auto',
    loop: true,
    loopedSlides: initSwiperSlidesLength,
    centeredSlides: true
  });
}

javascriptのコードの説明を簡単にしていきます。

1〜7行目はそれぞれ使う定数や変数を定義しています。

3行目がブレイクポイントで、800px以下だとswperが稼働するようにしています。

4行目は801px以上でも、swiperを稼働させる .swiper-slide の個数です。
ここではスライドの数が4つ以上になったときに、swiper を稼働させています。

成功例のほうにも書いていたのですが、7行目のmySwiperBool について説明します。

ブレイクポイントをまたいでもいないのに、ウィンドウ幅をリサイズするたびに、mySwiper.destroy や createSwipter() が実行されては困ります。

そこでウィンドウ幅のサイズと mySwiperBool のtrue/falseによって、リサイズした時に発火する関数を制御しています。

具体的は以下のような感じです。スライドの数は3個以下の前提です。


load時が1000pxのとき、mySwiperBool = false; (13行目)に設定されます。

resizeSwiper関数の35・36行目が801px以上のときに実行される内容ですが、ウィンドウ幅が801px以上 かつ、 mySwiperBool がtrue の時(34行目)にしか実行されません。

ですので、801px以上でいくらウィンドウ幅を動かしても、resizeSwiper関数の35・36行目の内容が実行されることはありません。

ここで800px 以下になると、38・39行目の内容が実行されます。
よってここで mySwiperBool = true; になります。

一度、38・39行目の内容が実行されてしまえば、ウィンドウ幅が800px以下 かつ、 mySwiperBool がfalse の時(37行目)にしか38・39行目の内容は実行されないので、800px以下でいくらウィンドウ幅を変えても、38・39行目の内容は実行されません。


以上のようにして、リサイズ時の関数の実行回数をできるだけ減らすために、mySwiperBoolを使用しています。

ここから、9〜30行目のロード時の内容について説明します。

まず10行目でスライド(.swiper-slide)の個数によって、条件分岐をしています。

スライドの数がswiperSize以下のときには11〜18行目の内容を実行しています。

まずswiperOuterに対して、「noSwiper」のクラスを付与しています。(11行目)

次にウィンドウ幅によって条件分岐していますが、breakPointより小さい場合には、createSwiper関数によって、swiperを稼働させています。(15行目)

リサイズ時に実行する関数(resizeSwiper)は、スライドの数がswiperSize以下のときにしか使用しないので、この条件分岐の中に入れています。(18行目)


次に、スライドの数がswiperSizeより大きい場合です。

まずswiperOuterに対して、「hasSwiper」のクラスを付与しています。(20行目)


次にlinkタグを取得しているのですが、swiper.cssを読み込んでいるlinkタグを修正したいので、ここで取得しています。(21行目)

htmlのときに、swiper.cssを読み込むlinkタグに「data-style="swiper"」を付けることが重要だといったのはここで使用するためです。(23行目)

swiper.cssはメディアクエリによって、800px以下でしか適用されないようにしていましたが、スライドの数がswiperSizeより大きい場合は801px以上でも使用するので、ここでmedia属性をallに変更します。(24行目)


32~42行目はresizeSwiper関数で、リサイズ時に実行されるをまとめたものです。

35行目のSwiperのdestoryメソッドですが、ちゃんとdestroy(false,true)にしましょう。falseとtrueの値が違うと、次にswiperを動かそうとした時にちゃんと動かなかったり、destroyされた後に、余計なstyleがついていたりします。

44行目以降は、普通にswiperを使用するときのオプションを設定していますが、スライドを固定幅で使用する時に気をつけることなどもこの中には入っています。

それはまた別記事で説明したいと思います。


以上、ブレイクポイントでSwiperの作成/解除を行うでした!

arrow_circle_up