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.
Kb azóta utálom, mióta bevezették a szánalmas-on. Biztos sokak szerint használható, de szerintem nem. Ha pl abbahagyod az olvasást és elmész mittomén fél órára valahova, majd visszajösz és szeretnéd folytatni ahol abbahagytad, akkor nem tudod. Tekerni kell és tekerni, majd tovább tekerni és akkor eccer talán meglesz ahol az elöbb abbahagytad. Idegesítő. Olyan ez mint a könyv, azt sem lapozod minden alkalomnál végig, hanem megjegyzed az oldalszámot. És legrosszabb esetben is azon oldalszám környékén keresel. Vannak persze szogáltatások, IRC, meg hasonló tipusú csevegős, esetleg “gyors” bejegyzéseket tartalmazó oldalak, amikhez használható lehet, de hál istennek a hétköznapi weblapoknál nem terjed ez a fajta lapozás
Thomas: Látod, az a rossz kivitelezés, illetve rossz helyen. Az egyik megoldás az lenne, hogy a weblap nyilvántartja, hogy mit olvastál már el, a másik pedig az, hogy engedi valahogy megjelölni, hogy hol tartottál (pl. rákattintasz az adott elem címére, és kapsz egy permalinket, ami az adott elemtől kezdi el töltögetni az elemeket). Egyébként szerintem te még nem láttad a Google Reader-t, ahol például nagyon jól használható ez a megoldás. Szerintem se kell mindenhol használni különben, de rosszul közelíted meg a kérdést, csevegős és hasonló oldalakhoz nem ezt a felállást kell használni (ott ahogy jön tartalom, meg kell jeleníteni, nem pedig akkor, ha odascrollozok – esetleg a régi hozzászólások esetén lehet így eljárni).
Én is utálom
deadcabbit: Mit utálsz benne?
Olyan, mintha egy könyvben nem tudnám, hanyadik oldalon járok… öreg vagyok én már és vaskalapos -_-
Én csak szánalmason láttam, máshol még nem. Engem leginkább az zavar benne, hogy egy adott oldal tartalma nem statikus.
Nem mondom, hogy rossz ötlet, de én csak egy másodlagos navigációnak tudom elképzelni, egy hagyományos lapozós navigáció mellett. Hozzáteszem én a lapozást is nagyon ritkán látom jól megoldottnak.
Par napja lattam, es szerintem is nagyon zavaro a deadcabbit altal leirt ok miatt: a scrollbar egyaltalan nem jelzi se azt, hogy hol tartasz, se azt, hogy mennyi adat van az oldalon.
Persze ez is megoldhato (kell elotte egy SELECT COUNT(*) – ha jol emlekszem a mezitlabas SQL-re), GUI vekony kliensek pl. szinte mindig ugy muxenek. De itt ujra feltalaljuk a spanyolviaszt, es ujra atelhetjuk ugyanazokat a UI szopasokat, mint 15-20 eve a vekony kliensekkel
. (Es hat valojaban nem is tortenik mas, mint hogy GUI vekony klienst gyartunk ujra.)
Az eszköz nagyon hasznos olyankor, amikor van is értelme használni. Ez persze mindenre igaz.
A Google Reader valóban jó példa, mivel ott mindet egyszer olvasol el, azaz onnan folytatod legközelebb, ahol abbahagytad. Ott, ahol csak szekkengetsz a listában és esetleg többször is visszatérsz, csak idegesíteni fog a dolog a fent leírtak szerint. MIndig ott van a baj, amikor valami “cool” dolgot az ember mindenáron használni akar.
Kommenteknél olyat tudok elképzelni, hogy ha az illető JK navigációval halad végig a kommenteken, bizonyos timeoput elteltével a bejegyzés olvasottá válik (ezt függővé lehet tenni a komment hosszától is, mert senki nem fog egy “ja, télleg” jellegű kommenten két másodpercet mélázni). Az olvasott hsz-eket pedig lehet rejteni és csak kérésre mutatni. Sima görgetés esetén pedig nem történik meg mindez az olvasottnak jelölés, mert nem mutat az user direktben rá egy hsz-re. Szóval lehetne ezt szerintem júzfúl módon is csinálni.
András görgetés figyelés megoldására: a folyamatos figyelgetés helyett az onscroll esemény nem lenne kézenfekvőbb?