【第7回】スライドショーを作ってみよう【jQuery講座】

jQuery講座

本シリーズは、jQueryの書き方を勉強し、その結果をまとめたものになる。

今回も引き続き、具体的な題材をjQueryで実装していく。

よく企業のページなどで見かける、スライドショーを実装してみよう。

なお、今回は難易度を分けて、二段階で実装する。

一つ目はシンプルに、時間経過で移り変わるだけのもの。

二つ目は、ボタン等による画像の切り替えや、条件によってスライドさせずに待ち続けるようなことも実装する。

まだ内容の理解に不安な方は一つ目だけで、自信のある方は二つ目にもチャレンジしてみてもらいたい。

スポンサーリンク

前回の内容の復習

前回は、サイドメニューを実装した。

これを使えば各情報を必要な時に必要なだけ出すことが可能となる。

cssは凝ってないのでシンプルな見た目になっているが、そこも調整することでよく使われているものも作ることができるだろう。

それも併せて挑戦してもらえればと思う。

以下がその記事だ。

スライドショー初級編

では、まず初級編から見ていこう。

こちらの機能はシンプル。

HTMLで用意されている画像について、それを時間経過によって順番に表示していくだけだ。

サンプルページ

サンプルページはこちら

ディレクトリ構造は以下のようになっている。

  • jquery
    • course-07_1.html
    • js
      • jquery-07_1.js
    • css
      • style-07_1.css

前回に引き続き、共通のstyle.cssは使用していない。

さて、ページを表示すると、まず画像が一枚表示される。

そして、一定時間ごとにその画像が切り替わっていくはずだ。

また、今回は4枚の画像を用意しており、最後まで表示しきったら最初の画像に戻ってくる。

サンプルソースは案外短く、以下の通り。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>jQuery講座第7回サンプルページその1</title>

        <!-- jQuery読み込み -->
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        <script type="text/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>

        <!-- 各回ごとのJavaScriptファイル読み込み -->
        <script type="text/javascript" src="./js/jquery-07_1.js"></script>

        <!-- 必要に応じてcssファイル読み込み -->
        <link rel="stylesheet" type="text/css" href="./css/style-07_1.css">
    </head>
    <body>
        <!-- ヘッダー -->
        <div class="header">
            <h1 id="page-title">jQuery講座第7回サンプルページその1</h1>
        </div>

        <!-- メインコンテンツ -->
        <div class="main-contents">
            <p>スライドショーレベル1</p>
            <p>時間経過で画像が切り替わるのみ</p>

            <!-- 画像表示用の領域-->
            <div class="slide-area">
                <img class="slide-contents" src="./img/course-07/slide-01.jpg">
                <img class="slide-contents" src="./img/course-07/slide-02.jpg">
                <img class="slide-contents" src="./img/course-07/slide-03.jpg">
                <img class="slide-contents" src="./img/course-07/slide-04.jpg">
            </div>
        </div>
    </body>
</html>
$(function(){
    /* --- 変数宣言パート --- */

    /* スライド画像部分を保持する変数 */
    var $slideContents = $(".slide-area").find(".slide-contents");

    /* スライドの枚数を保持する変数 */
    var slideNum = $slideContents.length;

    /* 現在表示しているスライド番号を保持する変数 */
    var nowSlide = 0;

    /* スライド変化にかける時間を保持する変数 */
    var durationSlideFade = 1000;


    /* --- 初期設定パート --- */

    /* 最初のスライドを表示させる */
    $slideContents.eq(nowSlide).fadeIn(durationSlideFade);

    /* タイマーをスタートさせる */
    setInterval(showNextSlide, 5000);


    /* --- 関数定義パート --- */

    /* 次のスライドを表示する */
    function showNextSlide(){
        var nextSlide = (nowSlide + 1) % slideNum;
        
        $slideContents.eq(nowSlide).fadeOut(durationSlideFade);
        $slideContents.eq(nextSlide).fadeIn(durationSlideFade);

        nowSlide = nextSlide;
    }
});
/* ページ全体の設定 */
body {
    margin: 0;
    font-family: "Avenir Next";
}

/* ヘッダー領域の設定 */
.header {
    padding-top: 1rem;
    padding-bottom: 1rem;
    background-color: black;
    color: white;
    text-align: center;
}

/* メイン表示領域の設定 */
.main-contents {
    width: 50%;
    margin: 0 auto;
}

/* スライドショー領域の設定 */
.slide-area {
    position: relative;
    margin-top: 1rem;
}

/* 各スライドの設定 */
.slide-area .slide-contents {
    display: none;
    position: absolute;
    width: 100%;
}

先に、HTMLとcssの中身を軽く解説。

まず、HTMLのスライドショー部分なのだが、シンプルに全体を囲むようにslide-areaクラスをつけたdivで囲む。

その中に、slide-contentsというクラスをつけた要素を入れることで、それがスライドショーの一つとして認識されるようになっている。

今回はここにあらかじめ4枚の画像を表示するようにしている。

で、画像ではなく別のタグでも、同じクラスをつければそれがスライドショーの一つになるので、テキストももちろん可能だ。

次に、cssについて。

処理に関わるポイントは二つあり、両方とも一番下のブロックだ。

ここはスライド1枚ごとの設定を行っているブロックになる。

一つ目は、display: none;最初はスライドを全て非表示にしていること。

jQuery側でフェードイン、フェードアウトさせることで、画像の切り替わりを表現することになる。

二つ目は、position: absolute;画像を全て重ねて同じ位置に配置していること。

これがないと、一旦下に次の画像が表示され、前の画像が消えたらそこに移動するような動きになってしまう。

気になる方は、この設定を一回消してどうなるか動きを見てみてほしい。

処理の流れ

では、jQueryの中身を見ていこう。

今回、大きく3つのパートに分けてみた。

最初は変数宣言パート、必要な変数はここで全て宣言している。

ここで、今後にも絡んでくる注意を一つ。

最初、$slideContentsという変数を用意し、その中に各スライドを表すjQueryオブジェクトを格納している。

このように、jQueryオブジェクトを入れる変数には、先頭に$マークをつけることにしよう。

こうすれば、どれがjQueryオブジェクトかが分かりやすくなる。

こうしなければいけないわけではないが、ソースを見やすくするためのものなので覚えておいて欲しい。

…さて、ここで使っているfindメソッドは初出なので解説していこう。

findメソッドは、今のjQueryオブジェクトの中から、さらに対象を絞る処理だ。

書き方は以下の通り。

find(セレクタ)

そのまま、これを呼び出したjQueryオブジェクトの中から、さらにセレクタに該当するようなjQueryオブジェクトが返される

今回、$(".slide-area").find(".slide-contents")という指定により、最初のセレクタ部分でslide-areaというクラス名がついたタグが取得される。

そして、次のfindメソッドでslide-contentsというクラス名がついたタグをその中から探してくることになる。

今回の場合は、$(".slide-area .slide-contents")と書いたのと同じことをしている。

で、例えばHTMLが以下のような状況。

<img class="slide-contents" src="">

<div class="slide-area">
    <img class="slide-contents" src="...">
    <img class="slide-contents" src="...">
</div>

この時に実行すると、1行目のimgタグは取得されず、div内の二つが取得できることになる。

…これだけだとfindメソッドを使うメリットがほとんどない。

だが、上級編で効力を発揮する部分も出てくるので、ここで使い方を確認しておいてほしい。

では、次に進んで二つ目の変数。

ここには、今取得したスライドの枚数を保持している。

現在、一つ目で取得したjQueryオブジェクトの中には、複数のタグ情報が入っている。

今回の例で言えば4つだ。

その時、jQueryオブジェクトのlengthにその数が格納されている

それを使って、スライドの枚数を取得しているのだ。

このような形にすることで、例えばHTML側で新たにスライドを追加しても、jQuery側はいじる必要がなくなる

メンテナンスの手間を減らすためにも、この形を使うようにしよう。

残りの変数はコメントに書いた通りなので省略させてもらう。

では、次の初期設定パートへ。

一つ目、最初のスライドを表示しているのだが、ここで二つ新たなメソッドを使っている。

まず、eqメソッド

これは、jQueryオブジェクトの中に複数のタグが含まれていたとき、その指定した番目の要素が入ったjQueryオブジェクトを取得するメソッドだ。

引数は、配列の添え字のようなイメージで指定すれば問題ない。

eq(数字)

要素は0番目からカウントされ、数字に書いた番目の要素を取得できる。

今回で言えば4つの要素が入っているので、0から3を書けば、その対応するタグが取得できる、という感じ。

で、次につなげているfadeInメソッド

これに対応するfadeOutメソッドも一緒に解説してしまおう。

これらは、特定のアニメーションを表現できる、animateメソッドの限定版みたいな感じ。

名前から分かるように、fadeInメソッドはフェードインを、fadeOutメソッドはフェードアウトを表現できる。

なお、fadeInメソッドは元の要素が非表示に、fadeOutメソッドは元が表示されている時にしか効かない。

これをするために、cssで全ての要素を最初非表示にしていたのだ。

今回の使い方は、全て引数を数字で一つ渡し、これでアニメーションにかける時間を指定している。

これは省略も可能で、その時はデフォルトで設定されている時間でアニメーションが再生されることを覚えておこう。

その他、関数を渡せばやはりそのアニメーション後に実行する処理を指定することもできる。

両方渡す場合は、時間、関数の順番だ。

fadeIn(時間, 関数)
fadeOut(時間, 関数)

ここまでの内容をまとめると、この1行でスライドそれぞれが入ったjQueryオブジェクトから最初のスライドを取得し、それに対してフェードインを行っていることになる。

似たようなことを後でもするので、覚えておこう。

その次、ここは前回まで使っていたsetTimeout関数ではないので注意。

このsetInterval関数はやはりJavaScript側の関数だ。

setInterval(処理, 間隔)

前回までのsetTimeout関数は、一定時間後に一度だけ処理を実行する処理だった。

それに対してsetInterval関数は、間隔に指定した時間ごとに、処理を繰り返し実行する、という処理になる。

例えば、この時間に3000を指定したとすると…

  • setInterval(test, 3000)実行 ※ここではtest関数は実行されない
  • 3秒待つ
  • test関数実行
  • 3秒待つ
  • test関数実行
  • 3秒待つ

こんな感じで動いてくれる。

一つ注意があるとすると、初回の実行前にも指定した時間待つというところだろうか。

そのため、最初にも実行したい場合は、別で処理を書く必要があるところに注意しよう。

今回の書き方は以下の通り。

setInterval(showNextSlide, 5000);

これで、5000ミリ秒ごと…5秒ごとに後で定義するshowNextSlide関数を実行する、という意味になる。

では、そのshowNextSlide関数を見ていこう。

ちょっとサンプルから離れてきているので、中身を再掲する。

/* 次のスライドを表示する */
function showNextSlide(){
    var nextSlide = (nowSlide + 1) % slideNum;
    
    $slideContents.eq(nowSlide).fadeOut(durationSlideFade);
    $slideContents.eq(nextSlide).fadeIn(durationSlideFade);

    nowSlide = nextSlide;
}

まず、先頭で次に表示するスライドが何番目かを取得している。

現在のスライド番号に1を足し、その後slideNumで割った余りを取得。

これで、最後以外であれば単純に次のスライド、最後であれば1を足すとslideNumと同じになるので割り切れて0が算出される。

次に、先ほど解説した二つのメソッドを使って、前の画像をフェードアウト、同時に次の画像をフェードインさせる。

最後、現在のスライド番号が変わったので、それを更新して処理完了だ。

これをsetInterval関数で5秒ごとに呼び出すことで、5秒ごとに画像が切り替わるスライドショーの完成だ。

そこまで難しいことはしていないと思うので、処理の流れをしっかり確認しておこう。

スライドショー上級編

上級編と書いたが、実際そこまで難しいわけではない。

ただ、やはりやることは増えるので、一個一個落ち着いて確認していきたい。

実装した内容

サンプルの前に、どんなことができるようにしたかを軽くまとめておく。

まず、スライドショーであるという点は当然ながら上と同じ。

しかし、画像の切り替わりをフェードイン・フェードアウトではなく、横にスライドする形にしている。

その他…

  • 左右のボタンで次や前の画像に切り替える
  • 画像の下に現在表示している画像の位置を表示する
  • その表示をクリックすることでも画像を切り替える
  • 一定時間でも画像を切り替えるが、カーソルを乗せている時はこれを無効にする

この4つの処理を追加した。

サンプルページ

では、サンプルページを見ていこう。

リンクはこちら、ディレクトリ構造は先ほどとファイル名以外は同じで以下の通り。

  • jquery
    • course-07_2.html
    • js
      • jquery-07_2.js
    • css
      • style-07_2.css

一度表示してみて、上に書いた動きになっていることを確認してほしい。

それぞれのソースは以下の通りだ。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>jQuery講座第7回サンプルページその2</title>

        <!-- jQuery読み込み -->
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        <script type="text/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>

        <!-- 各回ごとのJavaScriptファイル読み込み -->
        <script type="text/javascript" src="./js/jquery-07_2.js"></script>

        <!-- 必要に応じてcssファイル読み込み -->
        <link rel="stylesheet" type="text/css" href="./css/style-07_2.css">
    </head>
    <body>
        <!-- ヘッダー -->
        <div class="header">
            <h1 id="page-title">jQuery講座第7回サンプルページその2</h1>
        </div>

        <!-- メインコンテンツ -->
        <div class="main-contents">

            <!-- 画像表示用の領域 レベル2 -->
            <div class="contents">
                <p>スライドショーレベル2</p>
                <p>色々と機能を追加</p>
                <div class="slide-area">
                    <div class="slide-display">
                        <img class="slide-contents" src="./img/course-07/slide-01.jpg">
                        <img class="slide-contents" src="./img/course-07/slide-02.jpg">
                        <img class="slide-contents" src="./img/course-07/slide-03.jpg">
                        <img class="slide-contents" src="./img/course-07/slide-04.jpg">
                    </div>
                    <div class="slide-nav">
                        <p class="prev"><span><</span></p>
                        <p class="next"><span>></span></p>
                    </div>
                    <div class="slide-indicator">
                    </div>
                </div>
            </div>
        </div>
    </body>
</html>
$(function(){
    /* --- 変数定義パート --- */

    /* スライド領域全体を保持する変数 */
    var $slideAll = $(".slide-display");

    /* スライド画像部分を保持する変数 */
    var $slideContents = $slideAll.find(".slide-contents");

    /* インジケータ領域を保持する変数 */
    var $slideIndicatorArea = $(".slide-area .slide-indicator");

    /* インジケータのそれぞれの項目を保持する変数 */
    var $slideIndicator;

    /* スライドの枚数を保持する変数 */
    var slideNum = $slideContents.length;

    /* 現在表示しているスライド番号を保持する変数 */
    var nowSlide = 0;

    /* 自動で次のスライドに変化する時間を保持する変数 */
    var durationSlideChange = 5000;

    /* スライド変化にかける時間を保持する変数 */
    var durationSlideAnimation = 500;

    /* タイマー情報保持用変数 */
    var timerID;


    /* --- 初期設定パート --- */

    /* スライドを横並びに配置する */
    for(var i = 0; i < slideNum; i++){
        $slideContents.eq(i).css("left", (i * 960) + "px");
    }

    /* インジケータの中身をslideNumの数だけspanタグで追加する */
    /* 同時に、識別用のIDを表すタグも追加、これはcssで非表示に設定済み */
    for(var i = 0; i < slideNum; i++){
        $slideIndicatorArea.html($slideIndicatorArea.html() + "<span class='indicator-icon'>●<span class='indicator-id'>" + i + "</span></span>");
    }

    /* インジケータが用意できたので、そのjQueryオブジェクトを保持 */
    $slideIndicator = $(".slide-area .slide-indicator").find(".indicator-icon");

    /* 最初に表示されているインジケータにselectedクラスを追加 */
    $slideIndicator.eq(nowSlide).addClass("selected");

    /* タイマーをスタートさせる */
    startTimer();

    
    /* --- イベント登録パート --- */

    /* 進むボタンを押されたら次のスライドへ移る */
    $(".slide-area .slide-nav .next").on("click", showNextSlide);

    /* 戻るボタンを押されたら前のスライドへ移る */
    $(".slide-area .slide-nav .prev").on("click", showPrevSlide);

    /* インジケータが押されたらそのスライドへ移る */
    $slideIndicator.on("click", showSelectedSlide);

    /* 領域にカーソルが乗ったらタイマーをストップし、
       領域からカーソルが離れたらタイマーをスタートする */
    $slideAll.on({
        "mouseover": stopTimer,
        "mouseout": startTimer
    });
    

    /* --- 関数定義パート --- */

    /* nextSlideを受け取り、その画像へスライドさせる */
    function changeShowSlide(nextSlide){
        $slideIndicator.eq(nowSlide).removeClass("selected");
        $slideIndicator.eq(nextSlide).addClass("selected");
        $(".slide-display").stop(true).animate(
            {
                "left": "-" + (nextSlide * 960) + "px"
            },
            durationSlideAnimation
        );
        nowSlide = nextSlide;
    }

    /* 一つ次のスライドに移る */
    function showNextSlide(){
        var nextSlide = (nowSlide + 1) % slideNum;
        changeShowSlide(nextSlide);
    }

    /* 一つ前のスライドに移る */
    function showPrevSlide(){
        var nextSlide = (nowSlide + slideNum - 1) % slideNum;
        changeShowSlide(nextSlide);
    }

    /* インジケータがクリックされたとき、そのスライドに移る */
    function showSelectedSlide(){
        /* 注意:テキストのままだと後続処理に影響あり */
        var nextSlide = Number($(this).find(".indicator-id").text());
        changeShowSlide(nextSlide);
    }

    /* タイマーによるスライド変化を開始する */
    function startTimer(){
        timerID = setInterval(showNextSlide, durationSlideChange);
    }

    /* タイマーによるスライド変化を停止する */
    function stopTimer(){
        clearInterval(timerID);
    }

});
/* ページ全体の設定 */
body {
    margin: 0;
    font-family: "Avenir Next";
}

/* ヘッダー領域の設定 */
.header {
    padding-top: 1rem;
    padding-bottom: 1rem;
    background-color: black;
    color: white;
    text-align: center;
}

/* メイン表示領域の設定 */
.main-contents {
    width: 50%;
    margin: 0 auto;
}

/* コンテンツの設定 */
.contents {
    margin-top: 1rem;
}

/* スライドショー領域全体の設定 */
.slide-area {
    position: relative;
    width: 960px;
    height: 640px;
    overflow: hidden;
}

/* スライドショー部分領域の設定 */
.slide-area .slide-display {
    position: absolute;
    left: 0px;
    width: 100%;
    height: 100%;
}

/* スライドに表示する画像の設定 */
.slide-area .slide-display .slide-contents {
    position: absolute;
    width: 100%;
}

/* ナビゲーションボタンの設定 */
.slide-area .slide-nav p {
    position: absolute;
    top: calc(320px - 2.5rem);
    width: 5rem;
    height: 5rem;
    margin: 0;
    padding-top: -10px;
    border-radius: 2.5rem;
    background-color: lightgray;
    color: white;
    font-size: 4rem;
    opacity: 0.5;
    cursor: pointer;
}

/* ナビゲーションボタン中身のテキストの設定 */
.slide-area .slide-nav p span {
    position: absolute;
    top: -0.5rem;
}

/* ナビゲーション、戻るボタンの設定 */
.slide-area .slide-nav .prev {
    left: 1rem;
}

/* ナビゲーション、戻るボタン中身のテキストの設定 */
.slide-area .slide-nav .prev span {
    left: 0.75rem;
}

/* ナビゲーション、進むボタンの設定 */
.slide-area .slide-nav .next {
    left: calc(960px - 6rem);
}

/* ナビゲーション、進むボタン中身のテキストの設定 */
.slide-area .slide-nav .next span {
    left: 1rem;
}

/* インジケータの設定 */
.slide-area .slide-indicator {
    position: absolute;
    bottom: 2rem;
    width: 100%;
    text-align: center;
}

/* インジケータの色設定 */
.slide-area .slide-indicator .indicator-icon {
    color: skyblue;
    padding: 0 0.2rem;
    cursor: pointer;
}

/* インジケータに設定するIDの設定 */
.slide-area .slide-indicator .indicator-icon .indicator-id {
    display: none;
}

/* 現在表示している部分のインジケータの色設定 */
.slide-area .slide-indicator .selected {
    color: blue;
}

HTMLの構造を先に見ておく。

まず、全体をスライドショーエリアを表すslide-areaクラスをつけたdivで囲んでいる。

この中は、さらに3つのブロックに分かれている。

一つ目は画像表示の領域であるslide-displayクラスのdiv

この中に、初級編と同じくslide-contentsクラスでスライドを追加していく。

サンプルでは、初級編と同じ画像を入れてある。

二つ目は進む・戻るボタンを配置するslide-navクラスのdiv

中身はそのままprevクラス、nextクラスをつけた要素を入れている。

さらにspanで囲っているのは見た目調整用だ。

三つ目は、インジケータと呼ばれる領域。

処理の説明で、現在の画像の位置を表したり、その中をクリックしたりということを書いたが、その表示のことだ。

中身はスライドの枚数に対応して入れたかったので、jQuery側で操作するために、ここでは領域だけを確保している。

実際表示されたときにどうなっているかは、処理説明の中でお見せしよう。

で、cssに関しては…ちょっと記述量が多いし、今回の内容とは外れる部分も多いので、解説するのはやめておこう。

今回の処理用に設定している部分で補足が必要であれば、やはり処理説明の中で触れることにする。

処理の流れ

では、その処理を見ていこう。

初級編と同じくパートごとに分けているが、今回は以下の4つに分けた。

  • 変数定義パート
  • 初期設定パート
  • イベント登録パート
  • 関数定義パート

それぞれ見ていこう。

変数定義パート

ここでは今後使う変数を定義している。

中でやっていることは基本的にこれまで解説した内容で理解できるはず。

宣言している変数とその意味を一覧で出しておこう。

変数名意味
$slideAllスライド領域全体を保持する変数
$slideContentsスライド画像部分を保持する変数
$slideIndicatorAreaインジケータ領域を保持する変数
$slideIndicatorインジケータのそれぞれの項目を保持する変数
slideNumスライドの枚数を保持する変数
nowSlide現在表示しているスライド番号を保持する変数
durationSlideChange自動で次のスライドに変化する時間を保持する変数
durationSlideAnimationスライド変化にかける時間を保持する変数
timerIDタイマー情報保持用変数
今回使用する変数一覧

先頭に$マークがついているものはjQueryオブジェクトが入っていたことを思い出そう。

なお、最後のtimerIDって何ぞやと思われるかもしれないが、これは使う時に解説するので少し待っていて欲しい。

初期設定パート

では、初期設定を見ていこう。

まず、今回は横に移動させる形でスライドの変化を実装したい。

そのため、各スライドを横に繋げて配置するために、cssメソッドを使ってleftプロパティを調節している。

ここで、この座標は親であるslide-displayクラスの左を0とした数値であることに気を付けておいて欲しい。

cssではposition: absolute;がこれをするためのものだ。

これで、i番目の画像のleft画像サイズ×iで設定すれば横並びに配置できる。

詳しくはその時に解説するが、この状態でslide-displayleftを変更することにより、スライドを実現している。

次の処理は、インジケータの中身を定義だ。

元々、インジケータの領域には何も入っていなかった。

そこに、スライドの枚数だけ●を表示するようにHTMLを追加している。

この時のポイントが、この●がいくつ目を表すかの情報も同時に入れていること。

このアイコンの直後に、indicator-idクラスをつけたタグで情報を追加した。

cssでこれを非表示にしておけば、見た目には反映されずに情報を追加できる、という仕組みだ。

これで、今回の場合だとインジケータ領域のHTMLは以下のようになる。

<div class="slide-indicator">
    <span class='indicator-icon'>
        ●
        <span class='indicator-id'>0</span>
    </span>
    <span class='indicator-icon'>
        ●
        <span class='indicator-id'>1</span>
    </span>
    <span class='indicator-icon'>
        ●
        <span class='indicator-id'>2</span>
    </span>
    <span class='indicator-icon'>
        ●
        <span class='indicator-id'>3</span>
    </span>
</div>

これまた前回解説した内容だが、今回はしっかりHTMLタグとして入れたかったので、textメソッドではなくhtmlメソッドを使っていることにも注意。

これでインジケータの中身が入ったので、改めてその各項目を取得し、変数に代入している。

そして、インジケータでは現在表示されている部分の色を変えたい。

そこで、現在のインジケータをeqメソッドで取得し、selectedクラスを追加。

cssでselectedクラスがあるものの色を変更しているので、このクラス追加で色変更ができる。

ここで使っているaddClassメソッドも初出だ。

まあ名前から分かると思うが、これは対象のタグにクラスを追加するメソッドになる。

逆に指定したクラスを削除するremoveClassメソッドも併せて後で使うので覚えておこう。

addClass(クラス名)
removeClass(クラス名)

初期設定の最後は、タイマーのスタート。

これで、何もしなかったら一定時間でスライドさせる動きを開始している。

実際には関数を呼び出しているが、その中身は後で解説する。

以上が初期設定パートだ。

結局、インジケータ周りの処理と、自動スライドの開始をやっているだけなので、まだ困るようなことはないだろう。

関数定義パート

順番が前後して申し訳ないが、先に関数定義パートを見ていく。

というのも、イベント登録パートでは関数をガンガン使っているので、先にこちらを見た方が分かりやすいと思う。

もっと言えば、イベント登録パートは見ただけでほぼ分かるというのもある。

では早速一つ目から。

/* nextSlideを受け取り、その画像へスライドさせる */
function changeShowSlide(nextSlide){
    $slideIndicator.eq(nowSlide).removeClass("selected");
    $slideIndicator.eq(nextSlide).addClass("selected");
    $(".slide-display").stop(true).animate(
        {
            "left": "-" + (nextSlide * 960) + "px"
        },
        durationSlideAnimation
    );
    nowSlide = nextSlide;
}

ここは、次のスライドが何番目かを受け取って、それにスライドさせる処理を行う。

まず、インジケータのクラスを調整。

元々selectedクラスがついていたものを外し、次に表示する画像の部分へ追加。

その次は、現在アニメーション中ならそれを停止し、次の画像へアニメーションで移動させている。

ここで先ほど解説した通り、leftプロパティをマイナス方向へ動かすことにより表示する部分に画像を重ね合わせている

また、スライド領域全体にcssでoverflow: hidden;を設定しており、これで領域からはみ出した部分を非表示にした。

図で見ると以下のような感じだ。

スライド変化の様子

なお、この調節のために、画像は全て同じ大きさで揃えており、cssでも領域をその大きさに合わせている

最後、現在の表示スライドの番号を更新して完了だ。

次はスライドを一枚進める処理。

/* 一つ次のスライドに移る */
function showNextSlide(){
    var nextSlide = (nowSlide + 1) % slideNum;
    changeShowSlide(nextSlide);
}

初級編と同じ方法で次に表示するスライドが何番目かを算出し、それを使って一つ目の関数を呼び出している。

特に困ることはないだろう。

そして、今度はスライドを一枚戻す処理。

/* 一つ前のスライドに移る */
function showPrevSlide(){
    var nextSlide = (nowSlide + slideNum - 1) % slideNum;
    changeShowSlide(nextSlide);
}

異なるのはスライド番号の計算だけ。

今度はあらかじめslideNumを足しておき、そこから1を引く。

その状態でslideNumで割った余りを求めれば、次のスライドの番号が算出できる。

あとは上と同じく関数を呼び出して完了だ。

関数4つ目は、インジケータをクリックされたときのイベントハンドラ。

/* インジケータがクリックされたとき、そのスライドに移る */
function showSelectedSlide(){
    /* 注意:テキストのままだと後続処理に影響あり */
    var nextSlide = Number($(this).find(".indicator-id").text());
    changeShowSlide(nextSlide);
}

やはり次のスライド番号を受け取り、それに移動させるよう関数を呼び出している。

さて、ここはちょっと詳しく見ていこう。

まず、この関数はインジケータの各項目に対して、クリックイベントのイベントハンドラとして登録するものだ。

そのため、今クリックされた要素を取得するために、セレクタはthisを指定している。

で、この中にIDを入れる用のタグを仕込んでおいたので、それをtextメソッドで取得すれば、IDが得られる、という流れ。

ここでfindメソッドを使うことで、さらに中のタグが取得できる、ということ。

この部分はこれ以外では取得できない(やろうと思えばできるけど面倒)なので、これを使おう。

…さて、このtextメソッドで取得できるのは文字列だ。

後でこれを数字として計算式の中で使うことになり、コメントに書いた通りそのままだと不都合が生じる。

そこで、JavaScriptのNumber関数を使い、数値に変換している。

ここだけ注意すれば、あとは上二つと同じだ。

さて、残る二つはタイマー関連で、同時に見ていこう。

/* タイマーによるスライド変化を開始する */
function startTimer(){
    timerID = setInterval(showNextSlide, durationSlideChange);
}

/* タイマーによるスライド変化を停止する */
function stopTimer(){
    clearInterval(timerID);
}

これら単体ではjQueryを一切使っていないが、重要な箇所だ。

初級編で、setInterval関数を使えば一定時間ごとに処理を行えると書いた。

しかし、今回の上級編の処理では、それを止めたい。

その時に、setInterval関数の戻り値が必要となる。

ここでは、その一定時間ごとに行う処理がどれかを確定させるためのIDが発行される。

それを保持しておき、止める時はその値を指定する必要があるのだ。

clearInterval関数が、そのIDの処理を止める操作になる。

ということで、ここまで一度止めるというような書き方をしていたが、実際にはその一定間隔の処理を一旦破棄し、再開するときは新しく作る、という動きになっている。

実際に使う時は注意しよう。

イベント登録パート

では、最後に飛ばしたイベント登録パートを見ていこう。

とはいえ、先ほど書いた通りこれまでの内容や過去に解説した内容と照らし合わせてもらえれば、特に困るようなことはほとんどないだろう。

一つだけ、onメソッドで以前使っていない書き方をしているので、そこだけ解説を。

/* 領域にカーソルが乗ったらタイマーをストップし、
   領域からカーソルが離れたらタイマーをスタートする */
$slideAll.on({
    "mouseover": stopTimer,
    "mouseout": startTimer
});

最後のこの部分。

onメソッドに、オブジェクトを渡している。

このように、同じ対象に複数のイベントタイプ・イベントハンドラの組合せを登録したい場合は、それらを組み合わせたオブジェクトとして渡すことでも登録が可能だ。

書き方は以下。

on({
    イベントタイプ: イベントハンドラ,
    イベントタイプ: イベントハンドラ,
    ...
})

これも覚えておいてもらいたい。

もちろんだが、今回は以下のように書いても全く同じ動作になる。

$slideAll
    .on("mouseover", stopTimer)
    .on("mouseout", startTimer);

これで全体の解説が完了だ。

それぞれの動作について、どう処理を行っているかを紐づけて考えていこう。

おわりに

今回は、2種類のスライドショーを実装してみた。

それぞれの処理のために、どんなことをすればいいかが分かれば、そこまで難しくなかったと思う。

また、今回はただ画像でやったが、これにaタグを使えばそれぞれリンクを貼ることも当然可能。

その中身を用意すれば、だいぶそれっぽい形になるだろう。

さて、次回はスティッキーヘッダーを実現してみる。

スティッキーヘッダーとは、画面を下にスクロールしてもくっついてくるヘッダー領域のこと。

このブログ自体もそうだが、今ここを読んでもらっている時点でも一番上にメニューが表示されていると思う。

これを実装してみよう。

これまでの内容ももちろんだが、ここでも新しいメソッドが出てくるので、落ち着いて進めていきたい。

2021/2/22追記

次回の内容、スティッキーヘッダー編を公開した。

実装自体は非常にシンプルだが、jQueryではクラスのみを変更するという手法は覚えておくといいだろう。

また、プラグインを使って実現したスロットリングも重要なので、せめて名前だけでも把握しておきたい。

コメント

タイトルとURLをコピーしました