ギャラリーページで複数の要素に対して繰り返し処理ができません

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 915

takopo

score 288

前提・実現したいこと

初めてこちらに質問させていただきます。
今ページ内にある複数の画像を、数秒ごとに切り替わるギャラリーを作っていまして、
それぞれ違う数の画像を繰り返しフェードさせたいと思っています。

参考にしたのはこちら(http://on-ze.com/archives/1388)のページで、
このボックスをページ内に複数配置するイメージになります。
ボックスが1つの時はうまく動作するのですが、ボックスを増やすとなぜかエラーが出てしまいます。

いろいろ試してみたのですが、原因がどうしても分からず困っていまして、
どなたかご教授いただけますと大変助かります。

よろしくお願いいたします。

発生している問題・エラーメッセージ

ページを開くと、それぞれ1枚目の画像だけが表示されて、フェードインが始まりません。

該当のソースコード

■ html
<div class="box">
    <ul class="slide">
        <li><img src="first/01.jpg"></li>
        <li><img src="first/02.jpg"></li>
        <li><img src="first/03.jpg"></li>
    </ul>
</div>
<div class="box">
    <ul class="slide">
        <li><img src="second/01.jpg"></li>
        <li><img src="second/02.jpg"></li>
        <li><img src="second/03.jpg"></li>
        <li><img src="second/04.jpg"></li>
    </ul>
</div>
<div class="box">
    <ul class="slide">
        <li><img src="third/01.jpg"></li>
        <li><img src="third/02.jpg"></li>
        <li><img src="third/03.jpg"></li>
        <li><img src="third/04.jpg"></li>
        <li><img src="third/05.jpg"></li>
    </ul>
</div>

■ css
.slide {
    position: relative;
    width: 640px;
    height: 300px;
    margin: 0 auto;
}
.slide img {
    position: absolute;
    left: 0;
    top: 0;
}

■ js
$(function(){
  // 設定
  var $width = 640; // 横幅
  var $height = 300; // 高さ
  var $interval = 3000; // 切り替わりの間隔(ミリ秒)
  var $fade_speed = 1000; // フェード処理の早さ(ミリ秒)

  $('.box').each(function() {
    // 枠の位置を調整していったん消す
    $(this).find(".slide li").hide().css({"position":"absolute","top":0,"left":0});

    // 最初の画像に.activeクラスをつけて表示させる
    $(this).find(".slide li:first-child").addClass("active").show();

    // 画像を数秒おきにフェードインさせて、最後まで行くと最初の画像に戻って繰り返す
    setInterval(function(){
      // 現在の画像を変数に格納
      var $active = $(this).find(".active");
      console.log($active.html()); // ←ここがundefinedになってしまいます

      // activeの次に画像があればそれを、なければ最初の画像を$nextに格納
      var $next = $active.next("li").length ? $active.next("li") : $(this).find(".slide li:first-child");

      // 現在の画像をフェードアウトさせて.activeクラスを削除
      $active.fadeOut($fade_speed).removeClass("active");

      // 次の画像をフェードインさせて.activeクラスをつける
      $next.fadeIn($fade_speed).addClass("active");
    },$interval);
  });
});

試したこと

ボックスが1つだけの時は下の記述で動きました。
こちらでも複数のギャラリーは動くのですが、これだと全てのボックスが同時にスタートするため、
例えば3枚、4枚、5枚があった場合、3枚のボックスが先に終わってしまい、
他のボックスが全部終わるまで真っ白になってしまいます。
なので、ボックスがそれぞれ別々に動くように、eachメソッドを使って試しました。

$(function(){
  // 設定
  var $width = 640; // 横幅
  var $height = 300; // 高さ
  var $interval = 3000; // 切り替わりの間隔(ミリ秒)
  var $fade_speed = 1000; // フェード処理の早さ(ミリ秒)

  // 枠の位置を調整していったん消す
  $(".slide li").hide().css({"position":"absolute","top":0,"left":0});

  // 最初の画像に.activeクラスをつけて表示させる
  $(".slide li:first").addClass("active").show();

  // 画像を数秒おきにフェードインさせて、最後まで行くと最初の画像に戻って繰り返す
  setInterval(function(){
    // 現在の画像を変数に格納
    var $active = $(".active");
    console.log($active.html());

    // activeの次に画像があればそれを、なければ最初の画像を$nextに格納
    var $next = $active.next("li").length ? $active.next("li") : $(".slide li:first");

    // 現在の画像をフェードアウトさせて.activeクラスを削除
    $active.fadeOut($fade_speed).removeClass("active");

    // 次の画像をフェードインさせて.activeクラスをつける
    $next.fadeIn($fade_speed).addClass("active");
  },$interval);
});
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

こんな感じでどうでしょう。

$('.box').each(function() {
    var $_self = $(this); // これ以降の $(this) を $_self に置き換え
    // 枠の位置を調整していったん消す
    /* 略 */
});

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/12/17 15:20

    ご回答ありがとうございます!こちらの記述でうまく動作しました。
    thisを変数に置き換えればよかったんですね。
    なぜこのやり方がいいのか理解できていないので、少し調べてみたいと思います。
    初めてこのサイトで質問させていただいたのですが、
    すぐに回答が来て解決できたことに驚いています。
    本当にありがとうございました。

    キャンセル

  • 2016/12/17 15:26

    > なぜこのやり方がいいのか理解できていないので、少し調べてみたいと思います。
    JavaScript において this は結構難しいので、がんばってください!

    キャンセル

+2

$active.next("li").length の判定が良くないようです。次に画像がなくても、.lengthは0にはなりません。
判定には、$active.html()がundefinedになることを利用するようにしました。

$(function() {

    // 設定
    var $width = 640; // 横幅
    var $height = 300; // 高さ
    var $interval = 3000; // 切り替わりの間隔(ミリ秒)
    var $fade_speed = 1000; // フェード処理の早さ(ミリ秒)

    $('.box').each(function() {
        // 枠の位置を調整していったん消す
        $(this).find(".slide li").hide().css({
            "position" : "absolute",
            "top" : 0,
            "left" : 0
        });

        var $first_child = $(this).find(".slide li:first-child");

        // 最初の画像に表示させる
        var $active = $first_child.show();

        // 画像を数秒おきにフェードインさせて、最後まで行くと最初の画像に戻って繰り返す
        setInterval(function() {
            // activeの次に画像を$nextに格納
            var $next = $active.next();

            // activeの次に画像がなければ最初の画像を$nextに格納
            if (! $next.html()) {
                $next = $first_child;
            }

            // 現在の画像をフェードアウト
            $active.fadeOut($fade_speed);

            // 次の画像をフェードイン
            $next.fadeIn($fade_speed);

            $active = $next;
        }, $interval);
    });
});

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/12/17 16:48

    なるほどこういう方法もあるのですね。こちらでも無事動きました。
    $active.next("li").length の判定が良くないと分かり大変勉強になります。
    ご回答ありがとうございました!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.21%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる