Az “infinite scroll”, avagy a végtelennek tűnő oldalhosszúságot imitáló scroll megoldás ma már nem számít újdonságnak, a “Miner Reader” néven futó projektem kapcsán most én is elkezdtem implementálni egy ilyet. A lényeg az, hogy nagyon nagy adatmennyiségből valójában mindig csak éppen annyit teszink ki a böngészőben az olvasónak amennyit érdemes, és ahogy halad lefele az ember az oldalon, további részeket húzunk be a szerverről AJAX kérésekkel, szinte észrevétlenül. A konkrét megvalósítás sokféle lehet, most egy fapados következik.

A most bemutatandó script részletek még korántsem mondhatóak tökéletesnek, egyelőre csak gyors és látványos eredményt szerettem volna elérni, a finomhangolás (ami a nagyobb feladat lesz), még hátra van. Az alapokat a korábbi Google Reader szerű navigáció írásomból vettem, az adattartalom viszont most nem a Webakadémia blogbejegyzéseiből áll, hanem egy a szerver oldalról dinamikusan töltött tartalomból.
A cél és az eszköz
A cél az, hogy az oldalon történő J-K billentyűkkel történő mozgás során ha az oldal aljához közeledünk, akkor további elemeket töltsünk be. A J-K navigációt már jQuery-vel csináltam, így a feladat többi része is ezzel a könyvtárral készült. A JavaScript megírásán kívül szükségünk lesz még az adatokat szolgáltató szerver oldali scriptre is, a profi megvalósítást nem árt átgondolni, én egy adatbázis lekérdezés + LIMIT x, 10 kódra építettem az enyémet.
A tartalomszolgáltató
Egyszerű megoldásként azt választottam, hogy nem adatként, hanem kész HTML-ként küldöm a szerver felől a tartalmat a böngésző felé, így a kliens oldal egyszerűsödik egy kicsit, de a szerver oldal sem lesz agyonbonyolítva. A következő sematikus kód adja a szerver oldal lényegét:
$from = (int)$_GET['from'];
$data = mysql_query("select * from table limit ?,10", $from);
while($entry = mysql_fetch_array($data)) {
echo "<div class=\"entry\">";
echo "<div class=\"title\">".htmlspecialchars($entry['title'])."</div>";
echo "<div class=\"content\">".htmlspecialchars($entry['content'])."</div>";
echo "</div>";
}
A lényege a kódnak, hogy a from GET paraméter értéke szerint módosítja az SQL lekérdezés LIMIT-jét, és ez alapján tesz ki 10 elemet.
A kliens oldal
A kliens oldal sem egy túl bonyolult script, itt az oldal aljához közeledésének érzékelését a J-K navigációhoz kötöttem (hiba: a sima scroll tehát nem működik), és ha már csak három elem van hátra, akkor tölti be a következő 10 elemet. A betöltést egy load nevű függvény végzi el, egy “globális” változóban van nyilvántartva, hogy mennyi elem van éppen betöltve (és hogy honnan kell tölteni a következő tízet).
var num = 0;
function load() {
var div = document.createElement("div");
div.id = "content-"+num;
div.innerHTML = "<div class=\"entry\">Loading...</div>";
document.getElementById("content").appendChild(div);
jQuery("#content-"+num).load("data.php?from="+num);
num += 10;
}
jQuery(document).ready(function() {
load();
jQuery(document).keypress(function(e){if(e.target.tagName=='HTML'||e.target.tagName=='BODY'){
if (!e.altKey && !e.ctrlKey && (e.which==106 || e.which==107)) { // J and K
var titles = jQuery('.entry');
var c = jQuery(document).scrollTop();
var i = 0; while (i < titles.length && jQuery(titles[i]).offset().top - 10 <= c) { i++; }
if (e.which == 107) { i-=2; }
if (i >= 0 && i < titles.length) {
titles.removeClass('actual');
jQuery.scrollTo(jQuery(titles[i]).offset().top-10, 500, {easing:'swing'});
titles[i].className += ' actual';
if (i >= num-3) { load(); }
}
}
if (!e.altKey && !e.ctrlKey && e.which==108) { // L
load();
}
}});
});
A kódból a load() függvény, és annak meghívása a lényeges az “(i >= num-3)” feltételt tartalmazó sorból. A móka kedvéért még betettem egy L betűre lefutó függvényhívást is.
Hibák
A funkció “tökéletes” kivitelezését illetően persze vannak még bőven hiányosságok.
Azt már fentebb is említettem, hogy ha sima görgetéssel mozgunk az oldal aljára, akkor nem fog több tartalom betöltődni. Ezt egy másodpercenként többször lefutó kis függvénnyel oldhatjuk meg, ami az oldal éppen aktuális scroll pozícióját lekérdezi (lásd a fenti kódban a “c” változót), s amennyiben az oldal aljától 2-3 bekezdésnyi távolságra érünk, meghívja a load() függvény.
További probléma, hogy nincsen lekezelve az, hogy ha időközben friss tartalom kerül az adatbázisba – ilyenkor ismétlődések lehetnek az újonnan betöltött és a korábban már megérkezett tartalmakat illetően. Ezt többféleképpen is ki lehet kerülni, a megoldás főként az alkalmazástól függ, amit készítünk. Megoldás lehet például, hogy az oldal betöltődésekor egyből leküldünk 1000 id-t, és a betöltő script nem pozíció, hanem id alapján kéri le az elemeket. Egy másik, hogy szintén nem pozíciót, hanem a legutolsó id-t küldjük el a szerver oldal felé, amiből az meg tudja állapítani, hogy mely elem jön ezután a sorban.
Tovább
Attól függően, hogy mi a végső cél, elég sokmindent ki lehet hozni a fenti scriptekből, és persze bármelyik kliens oldali kódkönyvtárra könnyen lehet építkezni (a használt függvények jellemzően mindegyikhez megvannak), nem csak a jQuery-re. A fenti kódrészletek (értelemszerűen) szabadon felhasználhatóak.
Utolsó megjegyzések