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

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

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

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

jQuery

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

Q&A

解決済

1回答

1743閲覧

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

Chandler_Bing

総合スコア673

PHP

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

jQuery

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

0グッド

1クリップ

投稿2019/03/15 10:08

現在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に初期化されます。

JS

1$(function() { 2 // var array = []; 3 // var hotel = null; 4 var process = null; 5 var top = 0; 6 var normaltop = 0; 7 var sorttop = 0; 8 var normalFlag = false; 9 var sortflag = false; 10 var process = null; 11 var searchgtags = []; 12 13 14 function hotelClone() { 15 var hotel = $("<div>", { 16 "class": "hotel" 17 }); 18 var hotelpics = $("<div>", { 19 "class": "hotelpics" 20 }); 21 var mainpic = $("<div>", { 22 "class": "mainpic" 23 }); 24 var others = $("<div>", { 25 "class": "others" 26 }); 27 var hotelinfo = $("<div>", { 28 "class": "hotelinfo" 29 }); 30 var hotelname = $("<a>", { 31 "class": "hotelname" 32 }); 33 var tags = $("<div>", { 34 "class": "tags" 35 }); 36 var rating = $("<div>", { 37 "class": "rating" 38 }); 39 var rateposition = $("<span>", { 40 "class": "rateposition" 41 }); 42 var price = $("<div>", { 43 "class": "price" 44 }); 45 var clear = $("<div>", { 46 "class": "clear" 47 }); 48 49 hotelpics.append(mainpic, others); 50 rating.append(rateposition); 51 hotelinfo.append(hotelname, tags, rating, price); 52 result = hotel.append(hotelpics, hotelinfo, clear); 53 return result; 54 }; 55 56 function getHotels(process, index) { 57 return $.post('ajax.php', { 58 word: word, 59 kind: 'hotels', 60 process: process, 61 tags: searchgtags, 62 top: index 63 }); 64 }; 65 66 function getPics() { 67 return $.post('ajax.php', { 68 word: word, 69 kind: 'pics' 70 }); 71 }; 72 73 function getTags() { 74 return $.post('ajax.php', { 75 word: word, 76 kind: 'tags' 77 }); 78 }; 79 80 function getRates() { 81 return $.post('ajax.php', { 82 word: word, 83 kind: 'rate' 84 }); 85 }; 86 87 function displayHotels(process) { 88 process = process; 89 90 if (process === 'normal') { 91 normalFlag = true; 92 sortflag = false; 93 top = normaltop; 94 } else if (process === 'sortbyprice') { 95 sortflag = true; 96 normalFlag = false; 97 top = sorttop; 98 } 99 100 getHotels(process,top).done(function(result) { 101 hotels = result; 102 103 if (hotels.length > 0) { 104 if (normalFlag === true) { 105 normaltop = normaltop + hotels.length; 106 } else if (sortflag === true) { 107 sorttop = sorttop + hotels.length; 108 } 109 110 getPics().done(function(result) { 111 hotelpics = result; 112 113 getTags().done(function(result) { 114 hoteltags = result; 115 116 getRates().done(function(result) { 117 hotelrates = result; 118 119 var hotelsClone = []; //これから表示するホテルが入る 120 var hotelName = null; 121 var href = null; 122 var hotelMainPic = null; 123 var others1 = null; 124 var others2 = null; 125 var others3 = null; 126 var tags = []; 127 var rateWord = null; 128 var rate = null; 129 var price = null; 130 131 $.each(hotels, function(hotelindx, hotel) { 132 hotelsClone.push(hotelClone()); 133 hotelName = hotel.hotel_name; 134 href = 'about.php?hotelid=' + hotel.hotel_id + '&countrycode=' + hotel.country_code; 135 hotelsClone[hotelindx].find('.hotelname').append(hotelName); 136 hotelsClone[hotelindx].find('.hotelname').attr('href', href); 137 138 tags = []; 139 $.each(hoteltags, function(index, hoteltag) { 140 if (hotel.hotel_id === hoteltag.hotel_id && hotel.country_code === hoteltag.country_code) { 141 tags.push(hoteltag.tag); 142 } 143 }); 144 145 for (var i = 0; i < tags.length; i++) { 146 hotelsClone[hotelindx].find('.tags').append('<span>' + tags[i]); 147 } 148 149 price = hotel.price + '/1泊(1人)'; 150 $.each(hotelrates, function(index, hotelrate) { 151 if (hotel.hotel_id === hotelrate.hotel_id && hotel.country_code === hotelrate.country_code) { 152 rateWord = '口コミの評価' 153 rate = hotelrate.rate; 154 hotelsClone[hotelindx].find('.rating .rateposition').append('<span>' + rateWord); 155 hotelsClone[hotelindx].find('.rating .rateposition').append('<span class="rate">' + rate); 156 } 157 }); 158 hotelsClone[hotelindx].find('.price').append('<span>' + price); 159 160 $.each(hotelpics, function(index, hotelpic) { 161 if (hotel.hotel_id === hotelpic.hotel_id && hotel.country_code === hotelpic.country_code) { 162 hotelMainPic = '<img' + ' src' + '="' + 'imgs/' + hotelpic.main_pic + '">'; 163 others1 = '<img' + ' src' + '="' + 'imgs/' + hotelpic.others1 + '">'; 164 others2 = '<img' + ' src' + '="' + 'imgs/' + hotelpic.others2 + '">'; 165 others3 = '<img' + ' src' + '="' + 'imgs/' + hotelpic.others3 + '">'; 166 hotelsClone[hotelindx].find('.mainpic').append(hotelMainPic); 167 hotelsClone[hotelindx].find('.others').append(others1); 168 hotelsClone[hotelindx].find('.others').append(others2); 169 hotelsClone[hotelindx].find('.others').append(others3); 170 } 171 }); 172 hotelsClone[hotelindx].find('.mainpic img').height(300).width(300); 173 hotelsClone[hotelindx].find('.others img').height(85).width(85); 174 }); 175 for (var i = 0; i < hotelsClone.length; i++) { 176 $('.hotels .display').append(hotelsClone[i]); 177 } 178 hotelsClone = []; 179 top = 0; //念の為初期化 180 }); 181 }); 182 }); 183 } 184 }); 185 } 186 //ここまでメソッド 187 188 //最初の処理 189 displayHotels('normal'); 190 191 //ここからスクロール処理 192 $(window).on('scroll', function() { 193 // console.log('normaltop' + normaltop); 194 var doch = $(document).innerHeight(); //ページ全体の高さ 195 var winh = $(window).innerHeight(); //ウィンドウの高さ 196 var bottom = doch - winh; //ページ全体の高さ - ウィンドウの高さ = ページの最下部位置 197 //一番下までスクロールした時に実行 198 if (bottom <= $(window).scrollTop()) { 199 if (normalFlag === true && (normaltop % 5) == 0) { 200 displayHotels('normal'); 201 console.log('スクロール後のnormaltop' + normaltop); 202 } else if (sortflag === true && (sorttop % 5) == 0) { 203 displayHotels('sortbyprice'); 204 console.log('スクロール後のsorttop' + sorttop); 205 } 206 } 207 }); 208 209});

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

js

1<script> 2 $(function() { 3 4 var top = 0; //配列のインデックス(次に取得する値のインデックス) 5 var hotelsClone = []; //これから表示するホテルが入る 6 7 function hotelClone() { 8 var hotel = $("<div>", { 9 "class": "hotel" 10 }); 11 var hotelid = $("<p>", { 12 "class": "hotelid" 13 }); 14 var hotelname = $("<p>", { 15 "class": "hotelname" 16 }); 17 18 hotel.append(hotelid, hotelname); 19 return hotel; 20 }; 21 22 function getHotels(top) { 23 return $.post('scrollAjax.php', { 24 top: top 25 }); 26 }; 27 28 getHotels(0).done(function(hotels) { 29 30 if (hotels[1].length > 0) { 31 top = top + hotels[1].length; 32 $.each(hotels[1], function(index, hotel) { 33 hotelsClone.push(hotelClone()); 34 hotelsClone[index].find('.hotelid').text(hotel.hotel_id); 35 hotelsClone[index].find('.hotelname').text(hotel.hotel_name); 36 }); 37 for (var i = 0; i < hotelsClone.length; i++) { 38 $('.hotels .container').append(hotelsClone[i]); 39 } 40 hotelsClone = []; 41 } 42 }); 43 44 $(window).on('scroll', function() { 45 console.log('topは' + top + 'です'); 46 if ((top % 5) == 0) { 47 var doch = $(document).innerHeight(); //ページ全体の高さ 48 var winh = $(window).innerHeight(); //ウィンドウの高さ 49 var bottom = doch - winh; //ページ全体の高さ - ウィンドウの高さ = ページの最下部位置 50 51 if (bottom <= $(window).scrollTop()) { 52 //一番下までスクロールした時に実行 53 getHotels(top).done(function(hotels) { 54 55 if (hotels[1].length > 0) { 56 top = top + hotels[1].length; 57 $.each(hotels[1], function(index, hotel) { 58 hotelsClone.push(hotelClone()); 59 hotelsClone[index].find('.hotelid').text(hotel.hotel_id); 60 hotelsClone[index].find('.hotelname').text(hotel.hotel_name); 61 }); 62 for (var i = 0; i < hotelsClone.length; i++) { 63 $('.hotels .container').append(hotelsClone[i]); 64 } 65 hotelsClone = []; 66 } 67 }); 68 } 69 } 70 }); 71 }); 72</script>

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

再現できないので可能性として、ですが、$(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/19 02:45

moredeep

総合スコア1507

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Chandler_Bing

2019/03/22 10:07

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問