[jQuery] サムネイル付きのレスポンシブなスライドショーを作る方法

以前の記事「[jQuery] サムネイルをクリックするとメイン画像が入れ替わるレスポンシブ対応のギャラリーを作る」のギャラリーに自動再生機能と、ナビゲーションを付けてスライドショーにする方法です。

同じようなレスポンシブスライドショーの jQuery プラグインは既に多数ありますが、カスタマイズが必要な場合に多機能なプラグインだとコードをみてどこでなにをしているのかを理解するのが大変です…。今回もシンプルな機能なのでカスタマイズしやすいと思います。

サンプルデモ

◆ レスポンシブスライドショーデモ demo|memocarilog

このサンプルのコードは以下よりダウンロード出来ます。
◆ SaoriMiyazaki/ResponsiveSlideshow_jQuery

前回と同じく横幅が狭くなった場合のサムネイル画像は、設定した min-width まで小さくなり、並びきらない場合は以下のように2段になって表示します。
サムネイルが並びきらない場合は2段になって表示

HTML コード

画像をサムネイルサイズの画像と大きい画像と二種類用意します。

サムネイル画像をリスト形式で記入し ID 又は Class をふります。画像のリンク先を取得し、メイン部分へ表示するための画像の配列を作るため、サムネイルのリンク先に大きい画像ファイルのパスを記入します。

メイン画像を表示する為の div 要素を空で記入し、ID 又は Class をふります。サムネイルとメイン画像の部分を div で囲み、こちらもまた ID 又は Class をふります。

再生/停止ボタンとなる btn 要素をそれぞれ #play_btn/#stop_btn という ID 名で記入し、画像を送る/戻すボタンとなる btn 要素をそれぞれ #next/#prev という ID 名で記入します。記述場所はそれぞれを表示したい場所でOKです。このサンプルでは、画像の上に重ねたかった為メイン画像の div 内に記入してあります。

<!-- 全てをdivで囲む -->
<div id="photo_container">
	<!-- サムネイルの部分 -->
	<ul id="thumbnail">
		<!-- サムネイル画像のリンク先に大きい画像ファイルを指定する -->
		<li><a href="image/1.jpg"><img src="image/thumb/1.jpg" alt="photo1" /></a></li>
		<li><a href="image/2.jpg"><img src="image/thumb/2.jpg" alt="photo2" /></a></li>
		<li><a href="image/3.jpg"><img src="image/thumb/3.jpg" alt="photo3" /></a></li>
			:
	</ul>
	<!-- /#thumbnail -->
	
	<!-- メイン画像が表示される部分 -->
	<div id="main_photo">
	
        <!-- ナビゲーションの部分 -->
        <div class="img_nav">
            <btn id="next"></btn>
            <btn id="prev"></btn>
        </div>
        
        <!-- 再生/停止ボタン部分 -->
        <div class="ctr_btn">
            <btn id="play_btn">Play</btn>
            <btn id="stop_btn">Stop</btn>
        </div>
	</div>
	<!-- /#main_photo -->
	
</div><!-- /#photo_container -->

CSS コード

(前回と同じレイアウトなので、同じ説明ですが…。)

サムネイルの横並びには float を使っているため、親の ul 要素に overflow: hidden しています。img 要素はそれぞれ横幅を 100% にします。

メイン画像はクロスフェード表示するため一瞬の間2枚の画像を重ねて表示します。そのため、メイン画像 div 内の img に position: absolute の指定をし、メイン画像 div に img の高さを指定しておきます。

#thumbnail{
	overflow: hidden;
    width: 100%;
    	:
}
#thumbnail li{
    float: left;
    	:
}
#thumbnail li img{
    width: 100%;
	opacity: 0.5;
    filter: alpha(opacity=50); 
}
#thumbnail li.current img{
	opacity: 1;
    filter: alpha(opacity=100);
}
#main_photo{
	position: relative;
    height: 500px;
		:
}
#main_photo img{
	position: absolute;
	top:0;
	width: 100%;
}

ナビゲーションと、再生/停止ボタンのスタイルの記述です。画像を使うのが面倒だったので、ナビゲーション部分は border を使った矢印にしていますが、transform プロパティを使用しているため IE8 以下では上手く表示されません。

.img_nav btn{
    position: absolute;
    top:52%;
    margin: -25px 7% 0;
    width: 50px;
    height: 50px;
    border-top: solid 2px #fff;   
    border-left: solid 2px #fff;
    cursor: pointer;
}
#prev{
    -ms-transform: rotate(-45deg);
    -webkit-transform: rotate(-45deg);
    transform: rotate(-45deg);
}
#next{
    right: 0;
    -ms-transform: rotate(135deg);
    -webkit-transform: rotate(135deg);
    transform: rotate(135deg);
}
.ctr_btn{
    position: absolute;
    top:10%;
    right: 5%;
}

jQuery コード

jQuery 本体と以下のコードを head もしくは body 終了タグ直前に記入します。3行目からの options で div の ID やスライドスピードなど設定します。具体的な処理などはコード内のコメントにて説明しています。

前回のコード(「[jQuery] サムネイルをクリックするとメイン画像が入れ替わるレスポンシブ対応のギャラリーを作る」)と違う点は、自動再生機能・ナビゲーションの機能を追加したのでその部分と、メイン画像の表示方法です。今回はサムネイル画像とメイン画像をそれぞれ配列にし、現在表示中の画像の順番(変数 currentNum)に対応する配列のインデックスから画像を表示する方法になっています。

$(function(){
    // 設定
    var options = {
        thumbUl : $('#thumbnail'),  // サムネイルが入ったulのidを指定
        mainPhoto : $('#main_photo'), // メイン画像が入るdivのidを指定
        parentDiv : $('#photo_container'), // 全体を包むdivのidを指定
        slideSpeed: 3000, // 次の画像に切り替わるまでの時間
        fadeSpeed: 500, // フェードアニメーションの時間
        startPlay: true, // 最初から自動再生しておくかどうか
        maxWidth : 520, // parentDiv の max-width 値
        thumbMaxWidth : 80,  // サムネイルの max-width 値
        thumbMinWidth : 65 // サムネイルの min-width 値
    };
    
    // 変数作る
    var thumbs = options.thumbUl.find('a'),
        mainPhoto = options.mainPhoto,
        thumbFiles = [],
        mainFiles = [],
        currentNum = 0,
        nextBtn = $('#next'),
        prevBtn = $('#prev'),
        nowPlay = false, 
        timer,
        playBtn = $('#play_btn'),
        stopBtn = $('#stop_btn');       
	
    // ロード時 #main_photo に高さ設定
    window.onload = function(){
        mainPhoto.height(mainPhoto.children('img').outerHeight());
    }
    
    // 親Div サムネイルli メインDiv へmax-width・width値などを設定する
    options.parentDiv.css('maxWidth', options.maxWidth);
    var liWidth = Math.floor((options.thumbMaxWidth / options.maxWidth) * 100);
    options.thumbUl.children('li').css({
        width : liWidth + '%',
        maxWidth : options.thumbMaxWidth,
        minWidth : options.thumbMinWidth
    });
		
    // サムネイルとメイン画像の配列作る
    for(var i = 0; i < thumbs.length; i++){
        // メインの配列
        mainFiles[i] = $('<img />');
        mainFiles[i].attr({
            src: $(thumbs[i]).attr('href'),
            alt: $(thumbs[i]).children('img').attr('alt')
        });
        mainFiles[i] = mainFiles[i][0];
        // サムネイルの配列
        thumbFiles[i] = $(thumbs[i]).children('img');
        thumbFiles[i] = thumbFiles[i][0];
    }
    
    // メインに最初の一枚を表示しておく
    mainPhoto.prepend(mainFiles[0]);
    // サムネイルの最初の一枚の親 li に current クラスを付ける
    $(thumbFiles[0]).parent().parent().addClass('current');
    
    // ロード時の再生機能オンかどうかとボタンor停止ボタンの表示
    if(options.startPlay) {
        currentNum--;
        autoPlay();
        playBtnHide();
    } else {
        playBtnShow();
    }
    
    ////////// イベントの設定 ////////// 
    
    // サムネイルのクリックイベント
    thumbs.on('click', function(){
        // クリックしたサムネイルが thumbFiles の何番目になるのかを調べる
        currentNum = $.inArray($("img",this)[0], thumbFiles); 
        // 画像入れ替える関数実行
        mainView();
        // 自動再生は止める
        stopPlay();
        // 再生ボタンを表示
        playBtnShow();
        return false;
    });
    
    // プレビューボタンのクリックイベント
    prevBtn.on('click', function(){
        // currentNum を一個戻す
        currentNum--;
        // currentNum が最初まで戻ったら画像最後のインデックス数にする
        if(currentNum < 0){
			currentNum = mainFiles.length - 1;
		}
        // 画像入れ替える関数実行
        mainView();
        // 自動再生は止める
        stopPlay();
        // 再生ボタンを表示
        playBtnShow();
    });
    
    // ネクストボタンのクリックイベント
    nextBtn.on('click', function(){
        // currentNum を一個すすめる
        currentNum++;
        // currentNum が 最後まで行ったら 0 にする
        if(currentNum > mainFiles.length - 1){
			currentNum = 0;
		}
        // 画像入れ替える関数実行
        mainView();
        // 自動再生は止める
        stopPlay();
        // 再生ボタンを表示
        playBtnShow();
    });
    
    // 再生ボタンクリックイベント
    playBtn.on('click', function(){
		if(nowPlay) return;
        //自動再生オン
		autoPlay();	
		// ストップボタン表示
		playBtnHide();
	});
    
    // 停止ボタンクリックイベント
	stopBtn.on('click', function(){
		// 自動再生オフ
        stopPlay();
        // プレイボタン表示
        playBtnShow();
        
	});
    
    // ウィンドウサイズ変更時 mainPhoto の高さも変更
    $(window).on('resize', function(){
        mainPhoto.height(mainPhoto.find('img').outerHeight());
    });
    
    ////////// 関数の設定 //////////
    
    // メイン画像入れ替える関数
    function mainView(){
        // 画像を入れ替えて、古い方の画像はフェードアウトして削除
        mainPhoto.prepend(mainFiles[currentNum]).find('img').show();
        mainPhoto.find('img:not(:first)').stop(true, true).fadeOut(options.fadeSpeed, function(){
		    $(this).remove();
		});
        
        // クリックしたサムネイルへ current クラスを付けかえる
        thumbs.eq(currentNum).parent().addClass('current').siblings().removeClass('current');
    }
	
	// 自動再生の関数
    function autoPlay(){
        // 自動再生中は nowPlay を true にする
        nowPlay = true;
        currentNum++;
        if(currentNum > mainFiles.length - 1){
			currentNum = 0;
        }
        // 画像を入れ替える
        mainView();
        // タイマーで autoPlay() を繰り返し実行
        timer = setTimeout(function(){
        	autoPlay();
        }, options.slideSpeed);
	}
   
    // 自動再生止める関数
    function stopPlay(){
    	// タイマーをクリアに
        clearTimeout(timer);
        nowPlay = false;
    }
	
	// 再生ボタン表示非表示関数
	function playBtnShow(){
		// nowPlay が false なら playボタンを表示
        if(nowPlay === false){
        	stopBtn.hide();
			playBtn.show();
        }
	}
	function playBtnHide(){
		// nowPlay が true なら stop ボタンを表示
        if(nowPlay === true){
			playBtn.hide();
			stopBtn.show();	
        }
	}
    
});

Comments 5

  • イメージにぴったりのスライダーを見つけてとても助かっています。

    こちらのスライダーにキャプションもつけたいと思うのですが、
    jQueryのどこをいじればいいのでしょうか?

    https://memocarilog.info/jquery/7477
    こちらの記事も読んだのですが、
    jQueryもjsも初心者なもので、コードを書くことも読むこともほとんどできません・・・

    キャプションを付ける場合のjQueryコードとHTMLコードを教えていただけませんでしょうか?

    • taisuke さま

      コメント欄で具体的なコードの説明が難しいため、時間がある時にまた記事に追記できたらよいなと思います。

      • ご返答いただきありがとうございます!

        お手数おかけしますが是非ともよろしくお願いいたします!

  • とても参考になるサイトで、困った時いつも見ています。
    素晴らしいです。
    このスライドショーですが、画像を20枚ほどあげる場合、
    サムネイルがいっぱいできて3行ほど改行してしまうのを
    1列でnext‥とスクロールできたら
    もっと素敵だなぁと試行錯誤しているのですが、
    私の技量ではできません。

    やっぱり不可能なことでしょうか?
    もしお考えがあるなら教えていただけるとすごく嬉しいです。

    • chirorian さま

      ご参考くださりありがとうございます!

      このコードとは全く別物ですが、プラグインを使用したそのような動きのギャラリーのサンプルをご紹介したことがあります。
      jQueryで作る、サムネイルがカルーセルスライドするレスポンシブなイメージギャラリー
      この記事を書いたのがだいぶ以前なので、elastislide.js プラグインの使い方などがもしかしたら変わっているかもしれないので、ご使用の際はオフィシャルのページを一度ご確認いただいたほうがよいと思います。

      このコードのサムネイルもカルーセルにできないことはないと思いますが、一から作るのは少し時間がかかりそうですね。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です