jQuery でスライドショー

前回に引き続いて、jQueryネタ。
jQuery のエフェクト機能を使って、写真のスライドショーを実装してみた。
デモは、こんな感じ。

天日干し
お父さん袋
長男 PINGA Ver.
夜明け前
RECARO Start+i

元になる 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&#91;num_start&#93;).fadeOut(speed, function(){$(images&#91;num_next&#93;).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 難しいです。

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください