前回に引き続いて、jQueryネタ。
jQuery のエフェクト機能を使って、写真のスライドショーを実装してみた。
デモは、こんな感じ。
元になる HTML は、こんなです。
<div align="center" style="width:300px;height:140px;overflow:auto;"> <dl id="images"> <dd><img src='hogehoge1.jpg' /></dd> <dd><img src='hogehoge2.jpg' /></dd> <dd><img src='hogehoge3.jpg' /></dd> : </dl> </div>
で、javascript のソースはこんな感じ。
<script type='text/javascript'> $(function(){ $('#images').parent('div').attr('style','width:300px;height:140px;overflow:hidden;'); var images = $('dd', $('#images')).hide(); var images_count = images.length; // 指定した写真に移動するための関数 var img_rep = function(num_start, num_end, speed){ num_next = (num_start == num_end ? num_start : num_start + (num_start < num_end ? 1 : -1)); if (num_start != num_next) { $('img.move:visible', images).hide(); $(images[num_start]).fadeOut(speed, function(){$(images[num_next]).fadeIn(speed, img_rep_wrapper(num_next, num_end, speed));}); } else { $('img.move:hidden', images).show(); } } var img_rep_wrapper = function(num_start, num_end, speed){return function(){img_rep(num_start, num_end, speed);}} // 矢印アイコンの作成 var img_next = $('<img src="arrow-next.png" border="0" style="position:relative;float:right;margin:-1.6em 0.25em 0" alt="next" title="次へ" class="move" />'); var img_last = $('<img src="last.png" border="0" style="position:relative;float:right;margin:-1.6em 0.25em 0" alt="last" title="最後へ" class="move" />'); var img_prev = $('<img src="arrow-previous.png" border="0" style="position:relative;float:left;margin:-1.6em 0.25em 0" alt="prev" title="前へ" class="move" />'); var img_first = $('<img src="arrow-first.png" border="0" style="position:relative;float:left;margin:-1.6em 0.25em 0" alt="first" title="先頭へ" class="move" />'); // 矢印アイコンと click イベントを各写真に追加 var current = 0; images.each(function(){ if(current == 0){ $(this) .append(img_last.clone().click(img_rep_wrapper(current, images_count - 1, 'slow'))) .append(img_next.clone().click(img_rep_wrapper(current, current + 1, 'slow'))) .show(); } else if(current < images_count - 1) { $(this) .append(img_first.clone().click(img_rep_wrapper(current, 0, 'slow'))) .append(img_prev.clone().click(img_rep_wrapper(current, current - 1, 'slow'))) .append(img_last.clone().click(img_rep_wrapper(current, images_count - 1, 'slow'))) .append(img_next.clone().click(img_rep_wrapper(current, current + 1, 'slow'))) .hide(); } else { $(this) .append(img_first.clone().click(img_rep_wrapper(current, 0, 'slow'))) .append(img_prev.clone().click(img_rep_wrapper(current, current - 1, 'slow'))) .hide(); } current++; }); img_next.remove(); img_last.remove(); img_prev.remove(); img_first.remove(); }); </script>
困ったのは 26 〜 47行目で矢印アイコンにクリックイベントを付加するときの挙動。
最初は以下のように書きましたが、うまく行きませんでした。
var current = 0; images.each(function() { img_next.click(function(){img_rep(current, current + 1, 'slow');}); current++; });
これはクリックイベントが、イベント発生時の current
変数の値を参照して動作するからで、私の思惑通りに動作しませんでした。
# 変数のスコープ範囲をちゃんと理解してなかったんですね (T-T)
そうだ eval()
で書いちゃえば良いんぢゃん。ってことで、直した結果がこれ。
var current = 0; images.each(function() { img_next.click(eval("function(){img_rep(" + current + ", " + (current + 1) + ", 'slow');}")); current++; });
でも、IE6 では eval()
が function
を返してくれないようで、上手く動かず。
じゃぁ、function
を返す関数を作れば良いぢゃんってことで、落ち着いたのがこれ。
var current = 0; images.each(function() { img_next.click((function(a, b, c){}(return function(){img_rep(a, b, c);}).call(this, current, current + 1, 'slow')); current++; });
最初の無名関数は img_rep()
を指定された引数で呼び出す function
を返すためのもの。
call
メソッドですぐに自分を呼び出してます。
実際に実装する際は、こんな感じに落ち着きました。
var img_rep_wrapper = function(num_start, num_end, speed){return function(){img_rep(num_start, num_end, speed);}} var current = 0; images.each(function() { img_next.click(img_rep_wrapper(current, current + 1, 'slow')); img_prev.click(img_rep_wrapper(current, current - 1, 'slow')); img_first.click(img_rep_wrapper(current, 0, 'slow')); img_last.click(img_rep_wrapper(current, images.length - 1, 'slow')); current++; });
javascript 難しいです。