こんにちは、ユイトです(@mikiprogram)
画像やコンテンツを左右に切り替えるスライダーをshibajukuで学習しました。
学習のアウトプットとして記事に残していきます。
機能紹介
今回作成するスライダーの機能を紹介します。
- 「次へ」ボタンを押すとスライドして次の画像を表示
 - 「前へ」ボタンを押すとスライドして前の画像を表示
 
では、早速作っていきます!
完成コード
タブメニューになっているので切り替えると、CSS・jQueryのコードが表示されます。
完成コードはこちらです↓
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <title>コンテンツスライダー①</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="l-container">
      <h1 class="m-pageTitle">コンテンツスライダー①</h1>
      <div class="m-sliderWrap">
        <ul class="m-slider" id="js-slider">
          <li class="js-sliderItem m-slider__item">
            <img src="images/grape.jpg" alt="ぶどう" />
          </li>
          <li class="js-sliderItem m-slider__item">
            <img src="images/apple.jpg" alt="りんご" />
          </li>
          <li class="js-sliderItem m-slider__item">
            <img src="images/lemon.jpg" alt="レモン" />
          </li>
          <li class="js-sliderItem m-slider__item">
            <img src="images/pineapple.jpg" alt="パイナップル" />
          </li>
          <li class="js-sliderItem m-slider__item">
            <img src="images/strawberry.jpg" alt="いちご" />
          </li>
        </ul>
      </div>
      <!-- /.m-sliderWrap -->
      <ul class="m-sliderNav">
        <li class="m-sliderNav__item">
          <button class="m-button --prev" id="js-sliderPrevButton">前へ</button>
        </li>
        <li class="m-sliderNav__item">
          <button class="m-button --next" id="js-sliderNextButton">次へ</button>
        </li>
      </ul>
    </div>
    <!-- /.l-container -->
    <script
      src="https://code.jquery.com/jquery-1.12.4.min.js"
      integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="
      crossorigin="anonymous"
    ></script>
    <script src="app.js"></script>
  </body>
</html>
CodeSandBoxで簡単なデモページを作成しました!
※レスポンシブには対応していないので、恐れ入りますがPCからご覧ください。
HTML作成
スライドするためのコンテンツと、「前へ」・「次へ」ボタンを作成します。
<div class="l-container">
    <h1>コンテンツスライダー</h1>
    <div class="m-sliderWrap">
      <ul class="m-slider">
        <li class="m-slider__item">
          <img src="images/grape.jpg" alt="ぶどう">
        </li>
        <li class="m-slider__item">
          <img src="apple.jpg" alt="りんご">
        </li>
        <li class="m-slider__item">
          <img src="images/lemon.jpg" alt="レモン">
        </li>
        <li class="js-sliderItem m-slider__item">
          <img src="images/pineapple.jpg" alt="パイナップル" />
        </li>
        <li class="js-sliderItem m-slider__item">
          <img src="images/strawberry.jpg" alt="いちご" />
        </li>
      </ul>
    </div>
    <!-- /.m-sliderWrap -->
    <ul>
      <li><button>前へ</button></li>
      <li><button>次へ</button></li>
    </ul>
  </div>
<!-- /.l-container -->a要素とbutton要素の使い分け
・別のページにジャンプする機能が必要なときは、a要素を使用します。
・表示・非表示を切り替えるときは、button要素を使用します。
※個人的な使い分けの考えです。
スライドするコンテンツを横並び
主に、以下の3点をCSSで書いていきます。
l-containerにwidth:1000px;、margin: 3em auto;を指定して中央揃えにします。
m-sliderにdisplay:flex;でスライドするコンテンツを横並びにします。
 また、画像の合計枚数分のwidthを指定します。
m-sliderWrapに、overflow:hidden;で
見た目上、画像一枚分しか表示できないようにします。
.l-container {
    width: 1000px;
    margin: 3em auto;
}
.m-sliderWrap {
    overflow: hidden;
    /* 親要素である.l-containerの幅が800pxのため、widthを指定する必要なし */
}
.m-slider {
    display: flex;
    /* スライドする画像の合計幅を指定 */
    width: 3000px;
}m-sliderWrapのwidthについて
widthに関しては、親要素のl-containerの幅が1000pxのため、指定しなくても良いです。
理由は、ブロックレベル要素のwidthは初期値がautoだからです。
スライドの仕組みをイメージする
画像をスライドさせる方法として、positionプロパティを使用します。
m-sliderにposition:relative;を指定し、
画像一枚分の幅をleftに指定すると、二番目の画像が表示されます。
また、画像二枚分の幅をleftに指定すると三番目の画像が表示されます。
今回は、この動きを「前へ」・「次へ」ボタンをクリックしたときに動的に行うため、
JavaScriptを記述していきます。
.m-slider {
   //相対配置
    position: relative;
    //画像一枚分右に移動して2番目の画像が表示される
    left: -1000px;
    display: flex;
    width: 3000px;
}スライドのイメージ動画はこちら↓
※右下でleftの値を調整しています。
「前へ」・「次へ」ボタンのクリックイベント作成
JavaScriptで操作する用のid属性をHTMLに追加
追加する要素は以下の3点です。
ul要素にid属性js-sliderを追加します。
- 「前へ」の
button要素にid属性js-sliderPrevButtonを追加します。 
- 「次へ」の
button要素にid属性js-sliderNextButonを追加します。 
<div class="l-container">
    <h1 class="m-pageTitle">コンテンツスライダー</h1>
    <div class="m-sliderWrap">
      <ul class="m-slider" id="js-slider">
        <!-- 中身省略 -->
      </ul>
    </div>
    <!-- /.m-sliderWrap -->
    <!-- 省略 -->
</div>
<!-- /.l-container -->現在何枚目の画像を表示しているかを管理するための変数を作成
「現在何枚目の画像を表示しているか」管理するためのコンテンツ番号、変数indexに0を代入します。
$(function() {
  //現在のコンテンツ番号を管理
  var index = 0;
});「前へ」ボタンのクリックイベントを作成
まず、「前へ」ボタンをクリックするたびに、コンテンツ番号から1を引きます。
次に、js-sliderのleftの値をanimate() を使って変更します。
また、アニメーションを実行中にボタンを素早くクリックすると、
クリックした回数分だけアニメーションが継続されるので
アニメーションを止めるために、animate()の前にstop() を使用します。
$(function () {
    var index = 0;
    //「前へ」ボタンをクリックした時の処理
    $("#js-sliderPrevButton").click(function() {
        //現在のコンテンツ番号から1を引く
        index -- ;
        //leftの値をアニメーションで変更
        $("#js-slider").stop().animate({
            left: "-1000" * index
        },300);
    });
};「次へ」ボタンのクリックイベントを作成
まず、「次へ」ボタンをクリックするたびに、コンテンツ番号から1を足します。
それ以降の処理は、「前へ」ボタンと一緒です。
$(function () {
    var index = 0;
    $("#js-sliderPrevButton").click(function() {
        index -- ;
        $("#js-slider").animate({
            left: "-1000" * index
        },300);
    });
    //「次へ」ボタンをクリックした時の処理
    $("#js-sliderNextButton").click(function() {
        //現在のコンテン番号に1を足す
        index ++ ;
        //leftの値をアニメーションで変更
        $("#js-slider").stop().animate({
            left: "-1000" * index
        },300);
    });
};この時点で、
「次へ」ボタンを押すと、二枚目、三枚目と表示され、
「前へ」ボタンを押すと、三枚目、二枚目と表示され、機能としては完成しています。
しかし、今のままでは「次へ」ボタンを押し続けるとコンテンツが存在しなくても、
js-sliderが移動し続けてしまいます。「前へ」ボタンでも同様です。
そのため、コンテンツ番号を調整して、コンテンツが存在しない場所には
移動させないようにしていきます。
コンテンツが存在しない場所には、移動させない
今のままでは、コンテンツが存在しない場所でも移動できてしまうので、
以下のようにしたいと思います。
- もしも、最初のコンテンツで「前へ」ボタンがクリックされると、
 
最後のコンテンツに移動させます。
- もしも、最後のコンテンツで「次へ」ボタンがクリックされると、
 
最初のコンテンツに移動させます。
li要素にJavaScript操作用のclass属性を追加
li要素にJavaScript操作用のclass属性js-sliderItemを追加します。
<div class="m-sliderWrap">
   <ul class="m-slider" id="js-slider">
     <li class="js-sliderItem m-slider__item">
       <!-- 省略-->
     </li>
     <!-- 省略 -->
   </ul>
</div>
<!-- /.m-sliderWrap -->コンテンツの合計数を取得する
コンテンツの数を使って条件分岐を使いたいので、コンテンツの数を取得します。
$(function () {
    var index = 0;
    //コンテンツの数を取得
    var slideCount = $(".js-sliderItem").length;
    $("#js-sliderPrevButton").click(function() {
        index -- ;
        $("#js-slider").stop().animate({
            left: "-1000" * index
        },300);
    });
    $("#js-sliderNextButton").click(function() {
        index ++ ;
        $("#js-slider").stop().animate({
            left: "-1000" * index
        },300);
    });
};今回のコンテンツの数は、三個なので直接「3」を使って条件分岐できますが、
コンテンツの数が変わったときにメンテナンス性が悪いのでlength で取得した値を使います。
「前へ」ボタンの条件分岐
最初のコンテンツで「前へ」ボタンがクリックされると、
最後のコンテンツに移動したいので、
「現在のコンテンツ番号が0より小さいとき」のif文を書いていきます。
そして、0より小さいときは、コンテンツ番号をコンテンツ数から「1」引いた値にします。
$(function () {
    var index = 0;
    var slideCount = $(".js-sliderItem").length;
    $("#js-sliderPrevButton").click(function() {
        index -- ;
        //コンテンツ番号が0より小さいかチェック
        if(index < 0) {
           //コンテンツ番号をコンテンツ数から1引いた値にする。
           index = slideCount -1;
         }
        $("#js-slider").stop().animate({
            left: "-1000" * index
        },300);
    });
    $("#js-sliderNextButton").click(function() {
        index ++ ;
        $("#js-slider").stop().animate({
            left: "-1000" * index
        },300);
    });
};「次へ」ボタンの条件分岐
最後のコンテンツで「次へ」ボタンがクリックされると、
最初のコンテンツに移動に移動したいので、
「コンテンツ番号がコンテンツ数以上のとき」のif文を書いていきます。
そして、コンテンツ数以上のときは、コンテンツ番号を「0」にします。
$(function () {
    var index = 0;
    var slideCount = $(".js-sliderItem").length;
    $("#js-sliderPrevButton").click(function() {
        index -- ;
        if(index < 0) {
           index = slideCount -1;
         }
        $("#js-slider").stop().animate({
            left: "-1000" * index
        },300);
    });
    $("#js-sliderNextButton").click(function() {
        index ++ ;
        //コンテンツ番号がコンテンツ数以上のとき
        if(index > slideCount - 1) {
           //コンテンツ番号を0にする
           index = 0;
        }
        $("#js-slider").stop().animate({
            left: "-1000" * index
        },300);
    });
};重複している処理を関数化する
以上で今回したかった機能は実現することはできました。
しかし、「次へ」・「前へ」ボタンのクリックイベントを見てみると、animate()の部分や
if文は関数にまとめることができそうなので、処理をまとめていきます。
目的のコンテンツまで移動させる独自関数を作成
animate() の部分は「前へ」・「次へ」ボタンのどちらも同じ処理を行なっているので、
独自関数function sliding(){・・・}にまとめます。
まとめるだけだと、処理が実行されないのでsliding()で呼び出して実行します。
$(function () {
    var index = 0;
    var slideCount = $(".js-sliderItem").length;
    //目的のコンテンツまで移動させる独自関数
    function sliding() {
     $("#js-slider").stop().animate({
         left: "-1000" * index
        },300);
    }
    $("#js-sliderPrevButton").click(function() {
        index -- ;
        if(index < 0) {
           index = slideCount -1;
        }
        //独自関数の呼び出し
        sliding();
    });
    $("#js-sliderNextButton").click(function() {
        index ++ ;
        if(index > slideCount - 1) {
            index = 0;
        }
        //独自関数の呼び出し
        sliding();
    });
};条件分岐をまとめる
「前へ」・「次へ」ボタンのif文もsliding() に処理できるので、まとめます。
これ以上関数にまとめることができないので、今回はこれで完成です😄
$(function () {
    var index = 0;
    var slideCount = $(".js-sliderItem").length;
    //目的のコンテンツまで移動させる独自関数
    function sliding() {
     //if文をまとめる
     if(index < 0) {
        index = slideCount -1;
     }
     //if文をまとめる
     if(index > slideCount - 1) {
        index = 0;
     }
     $("#js-slider").stop().animate({
         left: "-1000" * index
        },300);
    }
    $("#js-sliderPrevButton").click(function() {
        index -- ;
        sliding();
    });
    $("#js-sliderNextButton").click(function() {
        index ++ ;
        sliding();
    });
};まとめ
今回は簡単なスライダーを作成しました。
重複している処理を関数にまとめて、コード量が短くなるとスッキリしていいですね!
次回は、自動でスライドする機能や画像の数が変わっても、
CSSでwidthを調整してなくて良い、メンテナンス性の高いスライダーを作りたいと思います!
最後まで読んでいただきありがとうございました🙇
