Det här är något som kvitteraren hade att säga.
jQuery är ett fantastiskt verktyg, men är det någonsin en tid då du inte ska använda den? I denna handledning ska vi titta på hur man bygger ett intressant rullningsbeteende med jQuery och sedan granska hur vårt projekt potentiellt kan förbättras genom att ta bort så mycket jQuery eller abstraktion som möjligt.
Ibland kan din kod vara ännu mer? Magisk? genom att subtrahera en del av den jQuery godheten.
Du kan förvänta dig att det här är din normala gör-något-awesome-med-jQuery handledning. Egentligen är det inte. Medan du kanske slutar bygga en ganska cool men, uppriktigt, kanske lika värdelös effekt, det är inte den viktigaste punkten jag vill att du ska ta bort från denna handledning.
Som du förhoppningsvis ser, vill jag att du ska lära dig att titta på jQuery du skriver som bara vanlig JavaScript, och inse att det inte finns något magiskt om det. Ibland kan din kod vara ännu mer? Magisk? genom att subtrahera en del av den jQuery godheten. Förhoppningsvis, i slutet av detta kommer du att bli lite bättre att utveckla med JavaScript än när du började.
Om det låter för abstrakt, överväg det här en lektion i prestanda och kodrefaktor? och stiger också utanför din komfortzon som utvecklare.
Här är vad vi ska bygga. Jag fick denna inspiration från den relativt nya Twitter för Mac-appen. Om du har appen (det är gratis), gå till någon persons kontosida. När du rullar ner ser du att de inte har någon avatar till vänster om varje tweet. Avatar för den första tweeten? följer? du som du rullar ner. Om du träffar en retweet ser du att den retweetade personens avatar placeras på rätt sätt bredvid hans eller hennes tweet. Då, när retweeterens tweets börjar igen, tar deras avatar över.
Det här är den funktionalitet som jag ville bygga. Med jQuery skulle det inte vara för svårt att sätta ihop, tänkte jag. Och så började jag.
Självklart, innan vi kan komma till showens stjärna, behöver vi lite markup att arbeta med. Jag kommer inte spendera mycket tid här, för det är inte huvudpunkten i denna handledning:
Twitter Avatar Scrolling Det här är något som kvitteraren hade att säga.
Det här är något som kvitteraren hade att säga.
Det här är något som kvitteraren hade att säga.
Det här är något som kvitteraren hade att säga.
Det här är något som kvitteraren hade att säga.
Det här är något som kvitteraren hade att säga.
Det här är något som kvitteraren hade att säga.
Ja, det är stort.
Vad sägs om vissa CSS? Prova detta:
kropp font: 13px / 1.5 "helvetica neue", helvetica, arial, san-serif; artikel display: block; bakgrund: #ececec; bredd: 380px; padding: 10px; margin: 10px; overflow: hidden; artikel img float: left; artikel p marginal: 0; padding-vänster: 60 bildpunkter;
Ganska minimal, men det kommer att ge oss vad vi behöver.
Nu vidare till JavaScript!
Jag tycker att det är rättvist att säga att detta inte är ditt genomsnittliga JavaScript widget-arbete; det är lite mer komplicerat. Här är bara några av de saker du behöver reda på:
När du börjar skriva något, oroa dig för att du bara får det att fungera. optimering kan komma senare. Version One ignorerade flera viktiga jQuery bästa praxis. Det vi börjar med här är version två: den optimerade jQuery-koden.
Jag bestämde mig för att skriva detta som ett jQuery-plugin, så det första steget är att bestämma hur det ska kallas; Jag gick med här:
$ (wrapper_element) .twitter_scroll (entries_element, unscrollable_element);
Det jQuery-objekt vi kallar plugin på, sveper "tweetsna"? (eller vad du rullar igenom). Den första parametern som plugin tar är en väljare för de element som kommer att bläddra: de? Tweets.? Den andra väljaren är för de element som håller på plats när det behövs (plugin förväntar sig att dessa är bilder, men det bör inte ta mycket justering så att det fungerar för andra element). Så, för den HTML som vi hade ovan kallar vi plugin så här:
$ ("avsnitt"). twitter_scroll ("artikel", ".avatar"); // OR $ ("section"). Twitter_scroll (". Avatar");
Som du ser när vi kommer till koden kommer den första parametern att vara frivillig; Om det bara finns en parameter, antar vi att det är den oscrollbara väljaren, och posterna är de direkta föräldrarna till unscrollablesna (jag vet att unscrollables är ett dåligt namn, men det är det mest generiska jag kan komma med).
Så här är vårt plugin-skal:
(funktion ($) jQuery.fn.twitter_scroll = funktion (poster, unscrollable) ; (jQuery));
Hädanefter kommer alla JavaScript vi tittar på att gå in här.
Låt oss börja med uppställningskoden; Det finns lite arbete att göra innan vi ställer in rullningsbehandlaren.
om (! unscrollable) unscrollable = $ (poster); poster = unscrollable.parent (); annars unscrollable = $ (unscrollable); poster = $ (poster);
Först parametrarna: Om unscrollable
är ett falskt-y-värde, ställer vi in det till? jQuerified? anteckningar
väljare och set anteckningar
till föräldrarna till unscrollable
. Annars ska vi? JQuerify? båda parametrarna. Det är viktigt att märka att nu (om användaren har gjort sin markering korrekt, vilket vi måste anta att de har), har vi två jQuery-objekt där matchande poster har samma index: så unscrollable [i]
är barnet av anteckningar [i]
. Detta kommer att vara användbart senare. (Notera: om vi inte ville anta att användaren markerade sitt dokument korrekt eller att de använde väljare som skulle fånga element utanför vad vi vill skulle vi kunna använda detta
som kontextparametern, eller använd hitta
metod av detta
.)
Låt oss nu ange några variabler. Normalt skulle jag göra det här högst upp, men flera beror på unscrollable
och anteckningar
, så vi behandlade det första:
var parent_from_top = this.offset (). top, entries_from_top = entries.offset (). top, img_offset = unscrollable.offset (), prev_item = null, starter = false, margin = 2, anti_repeater = null, win = $ ), scroll_top = win.scrollTop ();
Låt oss springa igenom dessa. Som du kanske kan tänka dig är kompensationen för de element vi jobbar med här viktiga. jQuery s offset
Metoden returnerar ett objekt med topp
och vänster
offset egenskaper. För moderelementet (detta
inuti plugin) och anteckningar
, Vi behöver bara den bästa offseten, så får vi det. För unscrollables behöver vi både topp och vänster, så vi kommer inte att få något specifikt här.
Variablerna prev_item
, förrätt
, och anti_repeater
kommer att användas senare, antingen utanför rullhanteraren eller inuti rullhanteraren, där vi behöver värden som kvarstår i samband med handlarens samtal. Till sist, vinna
kommer att användas på några ställen, och scroll_top
är avståndet från rullningsfältet från fönstret; Vi använder det senare för att bestämma vilken riktning vi rullar in.
Därefter kommer vi att bestämma vilka element som är första och sista i streck av? Tweets.? Det finns förmodligen ett par sätt att göra detta; Vi ska göra detta genom att ange en HTML5-dataattribut till lämpliga element.
entries.each (funktion (i) var img = unscrollable [i]; om ($ .contains (this, img)) if (img.src === prev_item) img.style.visibility = "hidden"; om (startar) poster [i-1] .setAttribute ("data-8088-starter", "true"); starter = false; om (! poster [i + 1]) poster [i] .setAttribute "data-8088-ender", "true"); annat prev_item = img.src; starter = true; om (poster [i-1] && unscrollable [i-1] .style.visibility === " dolda ") poster [i-1] .setAttribute (" data-8088-ender "," true ");); prev_item = null;
Vi använder jQuery s varje
metod på anteckningar
objekt. Kom ihåg att inuti funktionen passerar vi in, detta
avser det aktuella elementet från anteckningar
. Vi har också indexparametern, som vi ska använda. Vi börjar med att få motsvarande element i unscrollable
objekt och lagra den i img
. Då, om vår post innehåller det här elementet (det ska, men vi bara checkar), kontrollerar vi om källkoden för bilden är densamma som prev_item
; Om det är, vet vi att den här bilden är densamma som den i föregående post. Därför kommer vi att gömma bilden; Vi kan inte använda visningsegenskapen eftersom det skulle ta bort det från dokumentets flöde; vi vill inte att andra element flyttar på oss.
Då, om förrätt
Det är sant, vi ger anteckningen innan den här egenskapen data 8088-starter
; kom ihåg att alla HTML5-dataattribut måste börja med? data- ?; och det är en bra idé att lägga till ditt eget prefix så att du inte kommer att strida mot andra utvecklarers kod (mitt prefix är 8088, du måste hitta din egen :)). HTML5-dataattribut måste vara strängar, men i vårt fall är det inte de data vi är oroade över. vi behöver bara markera det här elementet. Sedan sätter vi på förrätt
till falskt. Slutligen, om det här är den sista posten, markerar vi det som ett slut.
Om bildkällan inte är densamma som källan till föregående bild, återställs vi prev_item
med källan till din nuvarande bild; då ställer vi start till Sann
. På det sättet, om vi finner att nästa bild har samma källa som den här, kan vi markera den här som starteren. Slutligen, om det finns en post före den här, och dess tillhörande bild är dold, vet vi att inmatningen är slutet på ett streck (eftersom den här har en annan bild). Därför ska vi ge det en dataattribut som markerar det som ett slut.
När vi är färdiga så ställer vi in prev_item
till null
; Vi kommer att återanvända det snart.
Nu, om du tittar på posterna i Firebug, bör du se något så här:
Nu är vi redo att arbeta på den här rullhanteraren. Det finns två delar i detta problem. Först hittar vi den post som ligger närmast överst på sidan. För det andra gör vi vad som är lämpligt för bilden relaterad till den posten.
$ (dokument) .bind ("scroll", funktion (e) var temp_scroll = win.scrollTop (), ner = ((scroll_top - temp_scroll) < 0) ? true : false, top_item = null, child = null; scroll_top = temp_scroll; // more coming );
Det här är vårt rullhanteringsskal; Vi har ett par variabler som vi skapar för att börja med; just nu notera ner
. Detta kommer att vara sant om vi rullar ner, falskt om vi rullar upp. Då återställer vi scroll_top
att vara avståndet från toppen som vi rullas till.
Nu, låt oss sätta top_item
att vara posten närmsta toppen av sidan:
top_item = entries.filter (funktion (i) var distance = $ (this). offset (). top - scroll_top; returnera (avstånd < (parent_from_top + margin) && distance > (parent_from_top - margin)); );
Det här är inte svårt alls. vi använder bara filtrera
metod för att bestämma vilken post vi vill tilldela top_item
. Först får vi distans
genom att subtrahera den mängd vi har bläddrat från den högsta förskjutningen av posten. Då återkommer vi sant om distans
är mellan parent_from_top + margin
och parent_from_top - margin
; annars, false. Om det här förvirrar dig, tänk på det så här: vi vill återvända sant när ett element står högst upp i fönstret; I detta fall, distans
skulle motsvara 0. Vi måste dock redogöra för den övre förskjutningen av behållaren som omsluter våra tweets ,? så vi vill verkligen distans
att lika parent_from_top
.
Men det är möjligt att vår rullhanterare inte kommer att skjuta när vi exakt är på den pixeln, men istället när vi är nära den. Jag upptäckte detta när jag loggade avståndet och fann att det var värden som var en halv pixel av; Om din rullhanteringsfunktion inte är för effektiv (som den här inte kommer att bli, ännu inte), är det möjligt att det inte kommer att skjuta på varje bläddra händelse. För att se till att du får en i rätt område lägger vi till eller subtraherar en marginal för att ge oss ett litet intervall att arbeta inom.
Nu när vi har toppunktet, låt oss göra något med det.
om (top_item) if (top_item.attr ("data-8088-starter")) om (! anti_repeater) child = top_item.children (unscrollable.selector); anti_repeater = child.clone (). appendTo (document.body); child.css ("synlighet", "dold"); anti_repeater.css ('position': 'fixed', 'top': img_offset.top + 'px', 'left': img_offset.left + "px"); annars om (top_item.attr ("data-8088-ender")) top_item.children (unscrollable.selector) .css ("synlighet", "synlig"); om (anti_repeater) anti_repeater.remove (); anti_repeater = null; om (! ned) if (top_item.attr ("data-8088-starter")) top_item.children (unscrollable.selector) .css ("synlighet", "synlig"); om (anti_repeater) anti_repeater.remove (); anti_repeater = null; annars om (top_item.attr ("data-8088-ender")) child = top_item.children (unscrollable.selector); anti_repeater = child.clone (). appendTo (document.body); child.css ("synlighet", "dold"); anti_repeater.css ('position': 'fixed', 'top': img_offset.top + 'px', 'left': img_offset.left + "px");
Du kanske märker att ovanstående kod är nästan samma sak två gånger; kom ihåg att detta är den ooptimerade versionen. När jag långsamt arbetade igenom problemet började jag med att räkna ut hur man rullar ner arbetet; När jag hade löst det arbetade jag på att rulla upp. Det var inte omedelbart uppenbart, tills all funktionalitet var på plats, att det skulle finnas så mycket likhet. Kom ihåg, vi optimerar snart.
Så, låt oss dissekera detta. Om toppunktet har en data 8088-starter
attribut, låt oss då kontrollera om anti_repeater
har ställts in; Detta är variabeln som kommer att peka på bildelementet som kommer att fixas när sidan rullar. Om anti_repeater
har inte ställts in, då får vi barnet vårt av top_item
post som har samma väljare som unscrollable
(nej, det här är inte ett smart sätt att göra det, vi förbättrar det senare). Sedan klonar vi det och lägger det till kroppen. Vi gömmer den där och placerar sedan den klonade en exakt var den ska gå.
Om elementet inte har en data 8088-starter
attribut, vi ska checka efter en data 8088-ender
attribut. Om det finns där hittar vi rätt barn och gör det synligt och tar sedan bort anti_repeater
och ställa in den här variabeln till null
.
Lyckligtvis, om vi inte går ner (om vi går upp), är det exakt det omvända för våra två attribut. Och om top_item
har inga attribut, vi är någonstans mitt i ett streck och behöver inte ändra någonting.
Tja, den här koden gör vad vi vill Men om du försöker det märker du att du måste rulla väldigt långsamt för att det ska fungera korrekt. Försök lägga till raderna console.profile ( "scroll")
och console.profileEnd ()
som första och sista linjerna i rullhanteringsfunktionen. För mig tar handlaren mellan 2,5ms - 4ms, med 166 - 170 funktionssamtal som äger rum.
Det är alldeles för länge för en rullhanterare att springa; och som du kan tänka dig kör jag det här på en ganska välutrustad dator. Observera att vissa funktioner kallas 30-31 gånger; vi har 30 poster som vi jobbar med, så det här är förmodligen en del av loopingen över dem alla för att hitta toppen. Det innebär att ju fler inträden vi har, desto långsammare kommer detta att springa; så ineffektivt! Så måste vi se hur vi kan förbättra detta.
Om du misstänker att jQuery är den främsta skyldige här, har du rätt. Medan ramar som jQuery är väldigt hjälpsamma och gör arbetet med DOM en bris, kommer de med ett kompromiss: prestanda. Ja, de blir alltid bättre. och ja, det är också webbläsarna. Vår situation kräver dock den snabbaste möjliga koden, och i vårt fall måste vi ge upp lite jQuery för ett direkt DOM-arbete som inte är alltför svårt.
Låt oss med den uppenbara delen: vad vi gör med top_item
när vi har hittat det. För närvarande, top_item
är ett jQuery-objekt; Men allt vi gör med jQuery med top_item
är trivialt hårdare utan jQuery, så gör vi det? raw.? När vi granskar fångsten top_item
, vi ska se till att det är en rå DOM-element.
Så här är vad vi kan ändra för att göra det snabbare:
getAttribute
metod istället för jQuery s attr
.unscrollable
som motsvarar top_item
post, istället för att använda unscrollable.selector
.clodeNode
och appendChild
metoder, istället för jQuery-versionerna.stil
egendom istället för jQuery s css
metod.removeNode
istället för jQuery's ta bort
.Genom att tillämpa dessa idéer slutar vi med detta:
om (top_item) if ((ner && top_item.getAttribute ("data-8088-starter")) || (! ner && top_item.getAttribute ("data-8088-ender"))) if (! anti_repeater) barn = unscrollable [entries.indexOf (top_item)]; anti_repeater = child.cloneNode (false); document.body.appendChild (anti_repeater); child.style.visibility = "hidden"; stil = anti_repeater.style; style.position = 'fixed'; style.top = img_offset.top + 'px'; style.left = img_offset.left + 'px'; om ((ner && top_item.getAttribute ("data-8088-ender")) || (! ner && top_item.getAttribute ("data-8088-starter"))) unscrollable [entries.indexOf (top_item)] .style.visibility = "visible"; om (anti_repeater) anti_repeater.parentNode.removeChild (anti_repeater); anti_repeater = null;
Det här är mycket bättre kod: inte bara blir det av det dubbletteret, men det använder också absolut ingen jQuery. (När jag skriver detta tänker jag att det kanske skulle vara lite snabbare att tillämpa en CSS-klass för att göra stylingen, du kan experimentera med det!)
Du kanske tror att det handlar om så bra som vi kan få; Det finns dock vissa seriösa optimeringar som kan äga rum när det gäller att komma igång top_item
. För närvarande använder vi jQuery s filtrera
metod. Om du tänker på det är det otroligt dåligt. Vi vet att vi bara kommer att få ett objekt tillbaka från denna filtrering; men filtrera
funktion vet inte det, så det fortsätter att köra element genom vår funktion efter att vi hittat den vi vill ha. Vi har 30 element i anteckningar
, så det är ett ganska stort slöseri med tid. Vad vi vill göra är detta:
för (i = 0; poster [i]; i ++) distance = $ (poster [i]). offset (). top - scroll_top; om (avstånd < (parent_from_top + margin) && distance > (parent_from_top - margin)) top_item = poster [i]; ha sönder;
(Alternativt kan vi använda en slinga med villkoret !top_item
; hur som helst, det spelar ingen roll så mycket.)
På så sätt, när vi hittar top_item
, vi kan sluta söka. Men vi kan göra det bättre; för att rulla är en linjär sak kan vi förutse vilket föremål som ligger närmast toppen nästa. Om vi rullar ner kommer det antingen att vara samma sak som förra gången, eller den efter den. Om vi rullar upp blir det samma föremål som förra gången, eller objektet före det. Det här kommer att vara användbart ju längre ner på sidan vi får, för loopen börjar alltid högst upp på sidan.
Så hur kan vi genomföra detta? Tja, vi måste börja med att hålla reda på vad top_item
var under vår tidigare körning av scroll-hanteraren. Vi kan göra det genom att lägga till
prev_item = top_item;
till slutet av rullningsfunktionen. Nu, upp där vi tidigare hittade top_item
, sätt detta:
om (prev_item) prev_item = $ (prev_item); höjd = höjd || prev_item.outerHeight (); om (ner && prev_item.offset (). topp - scroll_top + höjd < margin) top_item = entries[ entries.indexOf(prev_item[0]) + 1]; else if ( !down && (prev_item.offset().top - scroll_top - height) > (margin + parent_from_top)) top_item = poster [entries.indexOf (prev_item [0]) - 1]; annat top_item = prev_item [0]; annat för (i = 0; poster [i]; i ++) avstånd = $ (poster [i]). offset (). top - scroll_top; om (avstånd < (parent_from_top + margin) && distance > (parent_from_top - margin)) top_item = poster [i]; ha sönder;
Detta är definitivt en förbättring; om det fanns en prev_item
, då kan vi använda det för att hitta nästa top_item
. Matematiken här blir lite knepig, men det här gör vi:
prev_item
+ 1 för att hitta rätt element i anteckningar
).top_item
, vi använder vår för loop som en backning.Det finns några andra saker att ta itu med här. För det första, vad är det här höjd
variabel? Tja, om alla våra poster har samma höjd, kan vi undvika att beräkna höjden varje gång i rullhanteraren genom att göra det i inställningen. Så jag har lagt till det här i inställningen:
höjd = entries.outerHeight (); om (entries.length! == entries.filter (funktion () return $ (this) .outerHeight () === height;). längd) height = null;
jQuery s outerHeight
Metoden får höjden av ett element, inklusive det är vaddering och gränser. Om alla element har samma höjd som den första, då höjd
kommer att ställas in; annat höjd
kommer att vara null. Då när du får top_item
, vi kan använda höjd
om den är inställd.
Det andra att notera är detta: du kanske tror att det är ineffektivt att göra prev_item.offset (). top
dubbelt; Bör inte det gå in i en variabel. Faktum är att vi bara gör det en gång, för den andra om uttalandet kommer bara att ringas om ner
är falskt; Eftersom vi använder den logiska OCH-operatören, kommer de andra delarna av de två om de aldrig kommer att köras på samma funktionssamtal. Naturligtvis kan du lägga den i en variabel om du tycker att den håller din kod renare, men det gör inget för prestanda.
Men jag är fortfarande inte nöjd. Visst, vår rullhanterare är snabbare nu, men vi kan göra det bättre. Vi använder bara jQuery för två saker: för att få outerHeight
av prev_item
och för att få det bästa offsetet av prev_item
. För något så litet är det ganska dyrt att göra ett jQuery-objekt. Det finns emellertid inte en direkt uppenbar, icke-jQuery-lösning för dessa, som det fanns tidigare. Så, låt oss dyka in i jQuery-källkoden för att se exakt vad jQuery gör. På så sätt kan vi dra ut de bitar vi behöver utan att använda den dyra vikten av jQuery själv.
Låt oss börja med det största offsetproblemet. Här är jQuery-koden för offset
metod:
funktion (alternativ) var elem = detta [0]; om (! elem ||! elem.ownerDocument) return null; om (alternativ) return this.each (funktion (i) jQuery.offset.setOffset (detta alternativ, i);); om (elem === elem.ownerDocument.body) returnera jQuery.offset.bodyOffset (elem); var box = elem.getBoundingClientRect (), doc = elem.ownerDocument, body = doc.body, docElem = doc.documentElement, clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, topp = box.top + (self.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop) - clientTop, left = box.left + (self.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft) - clientLeft; returnera topp: topp, vänster: vänster;
Det ser komplicerat ut, men det är inte så illa. vi behöver bara den övre förskjutningen, inte den vänstra förskjutningen, så vi kan dra ut det här och använda det för att skapa vår egen funktion:
funktion get_top_offset (elem) var doc = elem.ownerDocument, body = doc.body, docElem = doc.documentElement; returnera elem.getBoundingClientRect (). top + (self.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop) - docElem.clientTop || body.clientTop || 0;
Allt vi behöver göra är att passera i det råa DOM-elementet, och vi kommer att få toppen offset tillbaka; bra! så vi kan ersätta alla våra offset (). top
samtal med den här funktionen.
Vad sägs om outerHeight
? Den här är lite svårare eftersom den använder en av de flera användningsområdena intern jQuery-funktioner.
funktion (marginal) returnera detta [0]? jQuery.css (denna [0], typ, false, margin? "margin": "border"): null;
Som vi kan se gör detta faktiskt bara ett samtal till css
funktion, med dessa parametrar: elementet,? höjd ?,? gräns ?, och falsk
. Så här ser det ut:
funktion (elem, namn, kraft, extra) if (name === "width" || namn === "height") var val, props = cssShow, which = name === "width"? cssWidth: cssHeight; funktion getWH () val = namn === "bredd"? elem.offsetWidth: elem.offsetHeight; om (extra === "gränsen") return; jQuery.each (vilken funktion () if (! extra) val - = parseFloat (jQuery.curCSS (elem, "padding" + detta, sant)) || 0; om (extra === "margin ") val + = parseFloat (jQuery.curCSS (elem," margin "+ detta, sant)) || 0; annars val - = parseFloat (jQuery.curCSS (elem," border "+ this +" Width " , sant)) || 0;); om (elem.offsetWidth! == 0) getWH (); annars jQuery.swap (elem, rekvisita, getWH); returnera Math.max (0, Math.round (val)); returnera jQuery.curCSS (elem, namn, kraft);
Vi kanske verkar hopplöst förlorade vid denna tidpunkt, men det är värt att följa logiken dock? eftersom lösningen är fantastisk! Visas, vi kan bara använda ett element offsetHeight
fast egendom; Det ger oss exakt vad vi vill ha!
Därför ser vår kod nu ut så här:
om (prev_item) height = height || prev_item.offsetHeight; om (ner && get_top_offset (prev_item) - scroll_top + height < margin) top_item = entries[ entries.indexOf(prev_item) + 1]; else if ( !down && (get_top_offset(prev_item) - scroll_top - height) > (margin + parent_from_top)) top_item = poster [entries.indexOf (prev_item) - 1]; annat top_item = prev_item; annat för (i = 0; poster [i]; i ++) distance = get_top_offset (poster [i]) - scroll_top; om (avstånd < (parent_from_top + margin) && distance > (parent_from_top - margin)) top_item = poster [i]; ha sönder;
Nu behöver ingenting vara ett jQuery-objekt! Och om du kör ner det, borde du vara långt under en millisekund och har bara ett par funktionssamtal.
Innan vi avslutar, här är ett användbart tips för att gräva runt i jQuery som vi gjorde här: använd James Padolsey's jQuery Source Viewer. Det är ett fantastiskt verktyg som gör det otroligt enkelt att gräva runt inuti koden och se vad som händer utan att vara alltför överväldigad. [Sidens anteckning: Ett annat bra verktyg du ska checka ut - jQuery Deconstructer.]
Jag hoppas att du har haft den här handledningen! Du kanske har lärt dig hur du skapar lite ganska snyggt rullningsbeteende, men det var inte huvudpunkten. Du borde ta bort dessa poäng från denna handledning:
Har några frågor? Eller kanske har du en idé om hur man förbättrar detta ännu mer! Låt oss diskutera det i kommentarerna!