jQueryを使ったスライドショーにて最後の画像で止めるスクリプト

検索するとjQueryを使ったスライドショーについてのページが色々ありますが、無限ループといった感じのページが多かったので、自分に合ったものを自作しました。
やりたかった事としては、指定ID内に存在する画像だけ分ループし、最後で止めるといったことです。
また、世間的には需要がないと思うけど、最後だけフェードの速度を遅くしたかったので、その処理も組み込みました。
プログラムカテゴリの過去を見ても分かるように、自分の知識がVBがメインでJavaScriptjQueryライブラリに詳しくないので、以下のページが参考になりました。


http://black-flag.net/jquery/20110525-3120.html


リンク先ページのコメント欄に最後の画像でスライドを止めるプログラムがあるのですが、それを参考にしました。
スクリプトが、読者様への取り急ぎ的な内容だったので、汎用性を持たせてなるべく制約を減らしました。
具体的には、画像数は指定して固定化しなくても存在する分切り替わるようにし、IDも画像の領域を確保するdivのID名さえ指定すれば動くようにしました。


以下プログラムですが、そのままテスト出来るようにJavaScriptCSSと画像素材を直書きしてHTMLでの掲載です。
テキストエディタにコピペして拡張子をhtmlで保存すればすぐに動作すると思います。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>SAMPLE</title>
<style type="text/css">
<!--
*{
	magin: 0;
	padding: 0;
}

#container{
	width: 100%;
	text-align: center;
}

#slideshow{
	visibility: hidden;
	margin: 0 auto;
	width: 500px;
	height: 200px;
	text-align: left;
	position: relative;
	overflow: hidden;
}
#slideshow img{
	top: 0;
	left: 0;
	position: absolute;
}
-->
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script type="text/javascript"><!--
$(function(){
	$(window).load(function(){
		//=================================================
		//	ユーザー設定
		var divID = 'slideshow'
		var fadeTime = 2000;
		var fadeTimeLast = 5000;
		var switchTime = 3500;
		//=================================================
		var objDiv = document.getElementById(divID);
		if (!objDiv){return;}
		var objImg = objDiv.getElementsByTagName('img');
		objDiv.style.visibility = 'visible';
		imgChange(objImg, fadeTime, fadeTimeLast, switchTime, 0);
	});
	function imgChange(objImg, fadeTime, fadeTimeLast, switchTime, cnt){
		if (cnt == 0){
			if (objImg.length == 0){return;}	//画像がない時
			$(objImg).css({opacity:'0'});
			$(objImg[cnt]).stop().animate({opacity:'1'},fadeTime);
			if (objImg.length == 1){return;}	//1枚だけの時
		} else if ((cnt == objImg.length - 1) && (objImg.length > 1)){
			for (i = 0; i <= 1; i++){$(objImg[(cnt - 1) + i]).stop().animate({opacity:i},fadeTimeLast);}
			return;
		} else {
			for (i = 0; i <= 1; i++){$(objImg[(cnt - 1) + i]).stop().animate({opacity:i},fadeTime);}
		}
		cnt++;
		setTimeout(function(){imgChange(objImg, fadeTime, fadeTimeLast, switchTime, cnt);},switchTime);
	};
});
//-->
</script>
</head>

<body>
<div id="container">

<div id="slideshow">
<img src="http://cdn-ak.f.st-hatena.com/images/fotolife/S/Shinez/20130424/20130424074133.jpg" alt="" width="500" height="200">
<img src="http://cdn-ak.f.st-hatena.com/images/fotolife/S/Shinez/20130424/20130424074130.jpg" alt="" width="500" height="200">
<img src="http://cdn-ak.f.st-hatena.com/images/fotolife/S/Shinez/20130424/20130424074128.jpg" alt="" width="500" height="200">
</div>

</div>
</body>
</html>

使い方

JavaScript


「ユーザー設定」とコメントアウトしてる部分の変数の値を指定します。
divIDはスライドショーをするために領域確保しているdivタグのID名を代入。
あとはスピードの調節に関する変数ですが、代入する数値がミリセカンドなので、1000で1秒です。
fadeTimeはフェードイン・アウトの時間、fadeTimeLastは最後の画像の時のフェードイン・アウトの時間、switchTimeは切り替わるタイミングの時間です。
最後のフェードは自分が個人的に実装したかっただけの自己満足で需要もないと思うので、不要であればfadeTimeと同じ値を入力すればそれまでと同じフェード時間になります。

HTML


divタグ内に好きなだけ画像を指定します。imgタグのID名は不要です。
JavaScriptでimg要素分ループするよう動的に処理するので、上に書いたimgタグから順番に表示されます。
スクリプト部で0枚だった時の処理もしてますが、その時は当然ながらタグ自体ないので表示されません。
1枚の場合は初めのフェードインだけで終わります。

CSS


HTML部でdivタグのID名を変更した場合は、CSSも変更して下さい。

プログラムの内容、流れ、解説

流れ


基本的には前述の通りdivタグのIDからオブジェクトを作成し、その中の画像要素分ループするだけのシンプルなものです。
しかし初めにフェードインから始まるので、それで若干ややこしくなってるかもしれません。
最初のフェードイン+その後の繰り返し切り替え動作となっているので、自分でそのことを忘れていてカウントしてる変数の数が合わずおかしいなぁと思ったりしてました(笑)
ループの2回目からが本来のループしたい1回目との認識で良いと思います。
文字だと説明が上手くいきませんね(笑)

再帰処理


画像要素分ループしたいので、初めはfor inとかのループで処理をしようと思ってました。
しかしデバッグしてみるとカウントの変数が何故か最大値のまま…。。
setTimeoutが怪しく思ったので調べたら、やはりこれが原因でした。
そういえば昔VBでもこれにあたるようなもので躓いたような記憶があります。
非同期というんでしょうか、処理の予約だけして次の処理に進んでしまいます。
指定した時間待機するSleep関数はJavaScriptにないようだし、どうしようかと調べたら、setTimeoutでループをさせたい場合は再帰的に処理すれば可能とのことが分かったので、結果そのように書きました。

visibility


CSSのvisibilityというプロパティは初め使ってなかったのですが、使わない場合最初のフェードが始まる前に最後の画像が見えてしまうことがあり、とりわけローカルよりも反応が遅いサーバーだとそれが顕著でした。
display: none;では領域もなかった事になってしまうので、表示だけ見えなくなるプロパティはないのかと探すと、visibility: hidden;で出来ました。
これをJavaScriptの処理が始まる段階でJavaScriptから操作してvisibleに切り替え表示させます。
今のところ問題なく、自分の思ったように動作してます。


追記


どうせ後にjQueryでopacityの値を動的に操作する訳なので、visibilityで隠しておくのではなく、opacityを0にしておいた方がスッキリしていいかもしれませんね。
スクリプト部分の「objDiv.style.visibility = 'visible';」が要らなくなります。



やさしくはじめるWebデザイナーのためのjQueryの学校

やさしくはじめるWebデザイナーのためのjQueryの学校