質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

90.50%

  • PHP

    22998questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • jQuery

    7757questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

jQueryで無限スクロールで表示件数がズレる

解決済

回答 1

投稿

  • 評価
  • クリップ 2
  • VIEW 75

YutaNkai

score 64

現在PHPとjQueryで無限スクロールを実装しています。挙動としてはスクロールが最下位部に到達すれば新たに5件追加するというものです。
でも作業では成功しましたが、以下に表示していファイルでは上手く行きません。

★問題

現在DBには14件表示できるデータ(ホテル)が入っています。まずページを読み込んだ時点で5件表示します。そして最下位部にくるとさらに5件表示します。そしてまた最下位部にくれば残りの4件を表示するので2回表示データの更新がありますが、ページを読み込んで次のデータ更新(最下位部到達による表示データの追加)で5件ではなく全てのデータを表示してしまいます。一気にデータを取ってきているのではなく最下位部到達が同時に起こってしまっています。
エラーも出ないのでどこが問題かわかりません。

★プログラム
変数topでDBからの取得位置を保持します。そしてデータを取得(Ajax経由)するとその件数を足し算し、次のデータ取得位置とします。

1,top = 0 //読み込み時
2,読み込み時に5件表示 //topが5に増加
3, 最下位部に到達
4,データをAjaxからデータを取得し表示しその件数をtopに追加 //topが10になる

このような感じです。

以下のjsのスクロール処理で連続して最下位部に到達するという原因はありますか。これだけで再現できませんがスクロールに所に問題があると仮定してお願いします。またこのページの変数ですが
var top = 0;
var normaltop = 0;
var sorttop = 0;
と3つの変数があります。文字数の条件で省いていますがこのjsにはクリック処理があります。normaltopは普通の表示です。sorttopは値段でソートした時のためです。topはAjaxに投げるデータです。処理の中でnormaltopかsorttopの取得位置をtopに代入しそれをAjaxに渡します。topは処理のあとは0に初期化されます。

$(function() {
  // var array = [];
  // var hotel = null;
  var process = null;
  var top = 0;
  var normaltop = 0;
  var sorttop = 0;
  var normalFlag = false;
  var sortflag = false;
  var process = null;
  var searchgtags = [];


  function hotelClone() {
    var hotel = $("<div>", {
      "class": "hotel"
    });
    var hotelpics = $("<div>", {
      "class": "hotelpics"
    });
    var mainpic = $("<div>", {
      "class": "mainpic"
    });
    var others = $("<div>", {
      "class": "others"
    });
    var hotelinfo = $("<div>", {
      "class": "hotelinfo"
    });
    var hotelname = $("<a>", {
      "class": "hotelname"
    });
    var tags = $("<div>", {
      "class": "tags"
    });
    var rating = $("<div>", {
      "class": "rating"
    });
    var rateposition = $("<span>", {
      "class": "rateposition"
    });
    var price = $("<div>", {
      "class": "price"
    });
    var clear = $("<div>", {
      "class": "clear"
    });

    hotelpics.append(mainpic, others);
    rating.append(rateposition);
    hotelinfo.append(hotelname, tags, rating, price);
    result = hotel.append(hotelpics, hotelinfo, clear);
    return result;
  };

  function getHotels(process, index) {
    return $.post('ajax.php', {
      word: word,
      kind: 'hotels',
      process: process,
      tags: searchgtags,
      top: index
    });
  };

  function getPics() {
    return $.post('ajax.php', {
      word: word,
      kind: 'pics'
    });
  };

  function getTags() {
    return $.post('ajax.php', {
      word: word,
      kind: 'tags'
    });
  };

  function getRates() {
    return $.post('ajax.php', {
      word: word,
      kind: 'rate'
    });
  };

  function displayHotels(process) {
    process = process;

    if (process === 'normal') {
      normalFlag = true;
      sortflag = false;
      top = normaltop;
    } else if (process === 'sortbyprice') {
      sortflag = true;
      normalFlag = false;
      top = sorttop;
    }

    getHotels(process,top).done(function(result) {
      hotels = result;

      if (hotels.length > 0) {
        if (normalFlag === true) {
          normaltop = normaltop + hotels.length;
        } else if (sortflag === true) {
          sorttop = sorttop + hotels.length;
        }

        getPics().done(function(result) {
          hotelpics = result;

          getTags().done(function(result) {
            hoteltags = result;

            getRates().done(function(result) {
              hotelrates = result;

              var hotelsClone = []; //これから表示するホテルが入る
              var hotelName = null;
              var href = null;
              var hotelMainPic = null;
              var others1 = null;
              var others2 = null;
              var others3 = null;
              var tags = [];
              var rateWord = null;
              var rate = null;
              var price = null;

              $.each(hotels, function(hotelindx, hotel) {
                hotelsClone.push(hotelClone());
                hotelName = hotel.hotel_name;
                href = 'about.php?hotelid=' + hotel.hotel_id + '&countrycode=' + hotel.country_code;
                hotelsClone[hotelindx].find('.hotelname').append(hotelName);
                hotelsClone[hotelindx].find('.hotelname').attr('href', href);

                tags = [];
                $.each(hoteltags, function(index, hoteltag) {
                  if (hotel.hotel_id === hoteltag.hotel_id && hotel.country_code === hoteltag.country_code) {
                    tags.push(hoteltag.tag);
                  }
                });

                for (var i = 0; i < tags.length; i++) {
                  hotelsClone[hotelindx].find('.tags').append('<span>' + tags[i]);
                }

                price = hotel.price + '/1泊(1人)';
                $.each(hotelrates, function(index, hotelrate) {
                  if (hotel.hotel_id === hotelrate.hotel_id && hotel.country_code === hotelrate.country_code) {
                    rateWord = '口コミの評価'
                    rate = hotelrate.rate;
                    hotelsClone[hotelindx].find('.rating .rateposition').append('<span>' + rateWord);
                    hotelsClone[hotelindx].find('.rating .rateposition').append('<span class="rate">' + rate);
                  }
                });
                hotelsClone[hotelindx].find('.price').append('<span>' + price);

                $.each(hotelpics, function(index, hotelpic) {
                  if (hotel.hotel_id === hotelpic.hotel_id && hotel.country_code === hotelpic.country_code) {
                    hotelMainPic = '<img' + ' src' + '="' + 'imgs/' + hotelpic.main_pic + '">';
                    others1 = '<img' + ' src' + '="' + 'imgs/' + hotelpic.others1 + '">';
                    others2 = '<img' + ' src' + '="' + 'imgs/' + hotelpic.others2 + '">';
                    others3 = '<img' + ' src' + '="' + 'imgs/' + hotelpic.others3 + '">';
                    hotelsClone[hotelindx].find('.mainpic').append(hotelMainPic);
                    hotelsClone[hotelindx].find('.others').append(others1);
                    hotelsClone[hotelindx].find('.others').append(others2);
                    hotelsClone[hotelindx].find('.others').append(others3);
                  }
                });
                hotelsClone[hotelindx].find('.mainpic img').height(300).width(300);
                hotelsClone[hotelindx].find('.others img').height(85).width(85);
              });
              for (var i = 0; i < hotelsClone.length; i++) {
                $('.hotels .display').append(hotelsClone[i]);
              }
              hotelsClone = [];
              top = 0; //念の為初期化
            });
          });
        });
      }
    });
  }
  //ここまでメソッド

  //最初の処理
  displayHotels('normal');

  //ここからスクロール処理
  $(window).on('scroll', function() {
    // console.log('normaltop' + normaltop);
    var doch = $(document).innerHeight(); //ページ全体の高さ
    var winh = $(window).innerHeight(); //ウィンドウの高さ
    var bottom = doch - winh; //ページ全体の高さ - ウィンドウの高さ = ページの最下部位置
    //一番下までスクロールした時に実行
    if (bottom <= $(window).scrollTop()) {
      if (normalFlag === true && (normaltop % 5) == 0) {
        displayHotels('normal');
        console.log('スクロール後のnormaltop' + normaltop);
      } else if (sortflag === true && (sorttop % 5) == 0) {
        displayHotels('sortbyprice');
        console.log('スクロール後のsorttop' + sorttop);
      }
    }
  });

});


ちなみにこのjsがデモで作成し上手くいったパターンです。ほぼ同じだと思います。デモなのでDB,Ajaxは使わずPHPの配列を使用指定ます。

<script>
  $(function() {

    var top = 0; //配列のインデックス(次に取得する値のインデックス)
    var hotelsClone = []; //これから表示するホテルが入る

    function hotelClone() {
      var hotel = $("<div>", {
        "class": "hotel"
      });
      var hotelid = $("<p>", {
        "class": "hotelid"
      });
      var hotelname = $("<p>", {
        "class": "hotelname"
      });

      hotel.append(hotelid, hotelname);
      return hotel;
    };

    function getHotels(top) {
      return $.post('scrollAjax.php', {
        top: top
      });
    };

    getHotels(0).done(function(hotels) {

      if (hotels[1].length > 0) {
        top = top + hotels[1].length;
        $.each(hotels[1], function(index, hotel) {
          hotelsClone.push(hotelClone());
          hotelsClone[index].find('.hotelid').text(hotel.hotel_id);
          hotelsClone[index].find('.hotelname').text(hotel.hotel_name);
        });
        for (var i = 0; i < hotelsClone.length; i++) {
          $('.hotels .container').append(hotelsClone[i]);
        }
        hotelsClone = [];
      }
    });

    $(window).on('scroll', function() {
      console.log('topは' + top + 'です');
      if ((top % 5) == 0) {
        var doch = $(document).innerHeight(); //ページ全体の高さ
        var winh = $(window).innerHeight(); //ウィンドウの高さ
        var bottom = doch - winh; //ページ全体の高さ - ウィンドウの高さ = ページの最下部位置

        if (bottom <= $(window).scrollTop()) {
          //一番下までスクロールした時に実行
          getHotels(top).done(function(hotels) {

            if (hotels[1].length > 0) {
              top = top + hotels[1].length;
              $.each(hotels[1], function(index, hotel) {
                hotelsClone.push(hotelClone());
                hotelsClone[index].find('.hotelid').text(hotel.hotel_id);
                hotelsClone[index].find('.hotelname').text(hotel.hotel_name);
              });
              for (var i = 0; i < hotelsClone.length; i++) {
                $('.hotels .container').append(hotelsClone[i]);
              }
              hotelsClone = [];
            }
          });
        }
      }
    });
  });
</script>
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+1

再現できないので可能性として、ですが、$(document).innerHeight()$(window).innerHeight()が整数なのに対し、$(window).scrollTop()が実数であることが原因となっている可能性があります。(Chromeで確認)
スクロールイベントのハンドラの先頭にでも各値を出力する処理を入れ、ほんの少しずつブラウザの縦幅をずらしてスクロールしてみると分かると思います。
例えば、console.log("bottom : " + ($(document).innerHeight() - $(window).innerHeight()) + ", scrollTop : " + $(window).scrollTop());のような処理です。
上記の出力結果を見ると、bottomよりもscrollTopの方が大きくなる可能性があることがわかります。bottomがscrollTop以下という条件に合致した後に、scrollTopがさらに大きくなったもう一度スクロールイベントに入ってきてしまう可能性があるのかなと。

原因は違うかもしれませんが、とりあえず、処理中であればdisplayHotelsを実行しないという判定を追加することで回避できるのではないでしょうか。

    //一番下までスクロールした時に実行
    // topは同期部で値を設定し、非同期の最後に初期化する。
    // 0でなければ非同期処理実行中ということ。!!failでの初期化必須!!
    if (bottom <= $(window).scrollTop() && top == 0) { 
      if (normalFlag === true && (normaltop % 5) == 0) {
        displayHotels('normal');
        console.log('スクロール後のnormaltop' + normaltop);
      } else if (sortflag === true && (sorttop % 5) == 0) {
        displayHotels('sortbyprice');
        console.log('スクロール後のsorttop' + sorttop);
      }
    }

蛇足ですが、二つ目のコードではAjaxを使用していないとのことですが、$.postを使用しているようです。
$.postは'$.ajax'のシンタックスシュガーですので、Ajaxは使用しています。
参考:$.post

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/03/22 19:07

    ありがとうございます。試してみます。

    キャンセル

同じタグがついた質問を見る

  • PHP

    22998questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • jQuery

    7757questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。