Lumina reflectoarelor Stickii constrânși cu jQuery

În fiecare săptămână, vom analiza cu atenție un aspect interesant și util, plugin, hack, bibliotecă sau chiar o tehnologie minunată. Vom încerca apoi fie să deconstruăm codul, fie să creăm un mic proiect distractiv.

Astăzi, vom analiza un plugin care implementează un efect destul de curat - este destul de greu de explicat într-o propoziție, astfel încât să puteți da click pe butonul Continuă pentru a începe după salt.


Un Cuvânt al autorului

În calitate de dezvoltatori web, avem acces la o sumă uimitoare de cod pre-construit, fie că este vorba de un fragment mic sau de un cadru complet. Dacă nu faci ceva incredibil de specific, există șanse, există deja ceva preconfirmat pentru a vă folosi. Din nefericire, multe dintre aceste oferte stelare se distrug în anonimitate, în special pentru mulțimea non-hardcore.

Această serie urmărește să remedieze această problemă introducând un cod cu adevărat bine scris și util - fie un plugin, un efect sau o tehnologie pentru cititor. Mai mult, dacă este suficient de mic, vom încerca să deconstruăm codul și să înțelegem cum o face voodoo. Dacă este mult mai mare, vom încerca să creăm un mini-proiect cu el pentru a învăța funiile și, sperăm, să înțelegem cum îl folosim în lumea reală.


Prezentarea stickyFloat

Iată câteva informații rapide:

  • Tip: Conecteaza
  • Tehnologie: JavaScript [Construit pe biblioteca jQuery]
  • Funcţie: Conținut plutitor numai în limitele constrângerilor părintelui său
  • Pagina de pornire a pluginului: Aici

Problema

În multe cazuri, aveți nevoie ca conținutul să plutească pe măsură ce defilați, dar numai în cadrul părintelui.

Conținutul plutitor, pe măsură ce un utilizator trece prin restul paginii, este copilul. Nu este necesar JavaScript - poți să o faci doar cu CSS vechi simplu. Slap a pozitie: fixa declarație și boom !, aveți un container care este fixat într-o anumită locație din pagină - plutește în pagină pentru a fi mai vorbitor.

Dar haideți să facem față, nu funcționează cu fiecare aspect. Ați putea să vă planificați un pic înainte și să o poziționați pe pagină, astfel încât să nu intervină niciodată cu elemente importante, dar nu ar fi complet protejat și nici reutilizabil în altă parte fără schimbări extinse.

În aceste cazuri, aveți nevoie ca conținutul să plutească pe măsură ce defilați, dar numai în cadrul părintelui.. Dacă vă întrebați, da, această funcționalitate este o variantă a celei pe care Andrew ți-a arătat-o ​​în tutorialul din săptămâna trecută, așa cum am aflat despre acest plugin.

Așa cum veți găsi în dezvoltarea web-ului, la fel ca și calculul multivariabil, există adesea o serie de soluții pentru orice problemă dată. Să ne uităm la una dintre acele soluții alternative.


Deconstruirea logicii

Logica generală sau fluxul de lucru al conectorului sunt de fapt destul de simple. Lasa-ma sa-ti arat. Rețineți că mă voi referi la elementul care trebuie să fie plutind ca lipicios de-acum inainte.

Dar înainte de a începe, iată un mockup rapid pentru a arăta ierarhia:

Întreaga logică a pluginului poate fi udată până la:

  • Calculați poziția curentă a elementului lipicios mamă, față de document. Marcat ca 1 în imagine.
  • Obțineți și înălțimea părintelui - Așadar, vom ști când să ne oprim când suntem pe lângă părinte. Marcat ca 2.
  • Calculați măsura în care pagina a fost derulată - Pentru a afla dacă ne uităm la părinte - pentru a vedea dacă suntem în raza de acțiune. În imaginea de mai sus, linia orizontală marchează partea superioară ipotetică a ferestrei de vizualizare curente. În acest caz, această valoare va fi distanța dintre punctele marcate ca 3.
  • Folosind cele două valori pe care le-am calculat mai sus, putem descoperi foarte repede dacă lipicioasa trebuie repoziționată corespunzător.

Dacă ești confuz, nu fi. De exemplu, să examinăm câteva exemple de numere:

  • Parintele lipicios este prezent 10px din partea de sus a paginii.
  • Părintele este 100px înalt.
  • Pagina a fost derulată 50px într - un scenariu și 150px in cealalta.

Deci, pe baza acestor informații de mai sus, puteți deduce acest lucru

În scenariul unu - lipicioasa ar trebui repetată corespunzător. De ce? Pagina a fost derulată 10px din partea de sus - 10 provine de la pagina în sine, în timp ce restul provine de la părintele lipicios. Astfel, părintele este vizibil în fereastra principală.

În scenariul doi - lipicioasa poate fi lăsată singură. Din cele 150 de pixeli, 10 provin de la pagină, 100 de elemente elementare, iar restul sunt preluate de restul elementului paginii. Aceasta implică faptul că utilizatorul a trecut prin părinte și nu trebuie să facem nimic.

Dacă încă nu sunteți îngrozit în acest moment, nu vă faceți griji. Voi explica un pic mai mult în timp ce mergeți prin sursă.


Deconstruirea sursei

Sursa dezbrăcat de comentarii este doar un smidgen peste 30 de linii lungime. Ca întotdeauna, vom trece prin cod și vom explica ceea ce face fiecare linie.

Iată sursa, pentru referință.

 $ .fn.stickyfloat = funcția (opțiuni, lockBottom) var $ obj = this; var părintePaddingTop = parseInt ($ obj.parent (). css ("padding-top")); var startOffset = $ obj.parent () offset () top; var opts = $ .extend (startOffset: startOffset, offsetY: parentPaddingTop, durata: 200, lockBottom: true, opțiuni); $ obj.css (poziție: 'absolut'); dacă (opts.lockBottom) var bottomPos = $ obj.parent () .înălțime () - $ obj.height () + parentPaddingTop; dacă (bottomPos < 0 ) bottomPos = 0;  $(window).scroll(function ()  $obj.stop(); var pastStartOffset = $(document).scrollTop() > opts.startOffset; var objFartherThanTopPos = $ obj.offset () sus> startOffset; var objBiggerThanWindow = $ obj.outerHeight () < $(window).height(); if( (pastStartOffset || objFartherThanTopPos) && objBiggerThanWindow ) var newpos = ($(document).scrollTop() -startOffset + opts.offsetY ); if ( newpos > bottomPos) newpos = bottomPos; dacă ($ (document) .scrollTop () < opts.startOffset ) newpos = parentPaddingTop; $obj.animate( top: newpos , opts.duration );  ); ;

E timpul să vedem ce face de fapt. O să presupun că aveți o bază destul de simplă a JavaScript-ului.

 $ .fn.stickyfloat = funcție (opțiuni, lockBottom) ;

Pasul 1 - Inventatorul generic pentru un plugin jQuery. După cum probabil știți, Opțiuni este un obiect care conține opțiuni asortate pentru a configura comportamentul pluginului. lockBottom, interesant, specifică dacă funcționalitatea pe care o dorim este activată sau nu. O vom lăsa pe loc.

 var $ obj = aceasta;

Pasul 2 - Mențineți o referință la elementul trecut. În acest context, acest indică elementul DOM care se potrivește cu selectorul în care ați trecut. De exemplu, dacă ați trecut #meniul, acest indică elementul cu ID-ul respectiv.

 var părintePaddingTop = parseInt ($ obj.parent (). css ("padding-top"));

Pasul 3 - Acest lucru este doar pentru a netezi efectul este elementul părinte are un padding mare. În caz afirmativ, acest lucru va include în calcul calculația.

 var startOffset = $ obj.parent () offset () top;

Pasul 4 - Calculam poziția părintelui față de document folosind ofset metoda jQuery. Lucrăm prin DOM folosind mamă metodă. Noi $ obj deoarece deja am cache-ul lipicios. Apăsați documentația API jQuery dacă nu sunteți familiarizat cu aceste metode.

În acest caz, distanța de la vârf este suficientă, astfel încât vom obține acea valoare singură.

 var opts = $ .extend (startOffset: startOffset, offsetY: parentPaddingTop, durata: 200, lockBottom: true, opțiuni);

Pasul 5 - O porțiune destul de generică a procesului de dezvoltare a pluginului jQuery. În mod esențial, fuzionăm în opțiunile trecute împreună cu unele presetări pentru a obține un set final de opțiuni care este utilizat în întregul cod. Rețineți că parametrii trecuți au întotdeauna prioritate față de valorile implicite.

 $ obj.css (poziție: 'absolut');

Pasul 6 - Efectul în cauză va fi creat prin manipularea elementului top Valoarea CSS, așa că vom merge mai departe și vom stabili poziția sa absolută în cazul în care nu a fost deja stabilită în acest mod.

 dacă (opts.lockBottom) var bottomPos = $ obj.parent () .înălțime () - $ obj.height () + parentPaddingTop; dacă (bottomPos < 0 ) bottomPos = 0; 

Pasul 7 - După cum sa menționat mai sus, lockBottom opțiunea specifică dacă efectul în cauză funcționează sau nu. Dacă este activată, putem începe calculul. Ceea ce calculam este punctul de delimitare dincolo de care nu ar fi nevoie să repoziționăm lipicioasa.

Firește, puteți trece prin calcularea înălțimii părintelui, dar efectul va fi nerăbdător. Veți avea nevoie să țineți cont de înălțimea lipicioasă însăși de-a lungul oricăror plăcuțe pe părintele însuși.

 $ (fereastră) .scroll (funcție () // Lot de cod

Pasul 8 - Ne-am legat codul, într-o funcție anonimă, sul eveniment. Acordat, acest lucru nu este cel mai eficient mod de a continua, dar o vom ignora deocamdată.

 $ Obj.stop ();

Pasul 9 - Prima ordine a cuvântului este de a opri toate animațiile care rulează pe elementul lipicios. Stop metoda se ocupă de acest lucru.

 var pastStartOffset = $ (document) .scrollTop ()> opts.startOffset; var objFartherThanTopPos = $ obj.offset () sus> startOffset; var objBiggerThanWindow = $ obj.outerHeight () < $(window).height();

Pasul 10 - Aceste trei variabile dețin valori pe care le vom folosi puțin mai târziu.

  • pastStartOffset verifică dacă am trecut prin limita superioară a elementului părinte. Amintiți-vă, am folosit ofset pentru a afla spațiul dintre elementul părinte și document. ObŃinem cât de departe te-ai derulat folosind scrollTop metodă. Aceasta este distanța dintre partea de sus a documentului și partea superioară a ferestrei de vizualizare curente.
  • objFartherThanTopPos verifică dacă lipicioasa se află în poziția implicită - în partea superioară a părintelui. Dacă am derulat dincolo de top a părintelui, nu vrem să plutească afară.
  • objBiggerThanWindow verifică dacă înălțimea totală a lipiciului este mai mare decât dimensiunea ferestrei. Dacă este așa, nu are rost să manipulezi elementul lipicios.
 dacă ((trecutStartOffset || objFartherThanTopPos) && objBiggerThanWindow) // Mai mult cod

Pasul 11 - Aici pluginul calculează dacă va trebui să manipulăm elementul lipicios. Ce face linia de mai sus:

  • Verificați dacă utilizatorul derulează exact în gama elementului părinte. Verificăm dacă utilizatorul se află sub limita superioară a părintelui sau, în caz contrar, lipicioasa este în partea de sus.
  • Așa cum am menționat mai sus, vom proceda numai dacă lipiciosul este mai mic decât dimensiunea ferestrei.

Procedăm numai dacă ambii din aceste condiții sunt îndeplinite.

 var newpos = ($ (document) .scrollTop () -startOffset + opts.offsetY);

Pasul 12 - Această linie definește o variabilă, et NewPos, care specifică poziția la care trebuie animat elementul lipicios. După cum ați observat, calculul este destul de fundamental dacă țineți cont de imaginea de mai sus. Aflați distanța derulată, adăugați suprapunerea părintelui la ea și, în final, scădeți distanța dintre document și părinte - punctul de pornire. Acest lucru vă oferă distanța, în pixeli, între partea superioară a elementului părinte și punctul din interior, în cazul în care lipiciosul trebuie poziționat.

 dacă (newpos> bottomPos) newpos = bottomPos;

Pasul 13 - Dacă am derulat dincolo de limita inferioară a elementului părinte, nu este nevoie să manipulăm în continuare lucrurile. Blocați poziția sa acolo.

 dacă ($ (document) .scrollTop () < opts.startOffset ) newpos = parentPaddingTop;

Pasul 14 - Dacă am derulat deasupra limitei superioare a părintelui, păstrați-l blocat acolo, astfel încât să nu se miște mai sus.

 $ obj.animate (top: newpos, opts.duration);

Pasul 15 - Totul este gata! Pur și simplu animăm elementul lipicios care trece prin cerințele necesare top valoare, împreună cu durata efectului folosind anima metoda jQuery.


folosire

Așa cum ați putea probabil deduce în acest moment, utilizarea este așa:

 $ ("meniu"). stickyfloat (duration: 500);>

În loc să explicăm exemplul mini-proiectului, ca și ultima oară, am decis în schimb să construiesc și să vă dau codul.

Iată părțile relevante ale demo-ului, restul este boilerplate:

HTML-ul

 
Meniul lipicios
Am vrut să scriu ceva incredibil, nemaivăresc de aici. Am esuat. :(
Da, te voi urmări oriunde ai fi în părintele meu
Ai așteptat ceva deștept aici, nu-i așa? Știu că ai făcut-o! Fess sus!

CSS

 .secțiune padding: 10px; lățime: 900px; marja: 0 auto; background-color: # f1f1f1; Poziția: relativă;  .secția .content height: 800px; culoare de fundal: #ddd; margin-left: 250px; text-align: center; Culoare: # 333; font-size: 16px;  .secție .menu poziție: absolută; stânga: 10px; lățime: 240 de pixeli; height: 100px; fundal: # 06C; text-align: center; Culoare: #fff; font-size: 14px; 

JavaScript

 $ ("meniu"). stickyfloat (duration: 400); $ ('# menu2'). stickyfloat (duration: 400);

Dacă treceți prin fișiere în timp ce citiți acest articol, ar trebui să fie destul de auto-explicativ, dar sunteți mai mult decât binevenit să mă lovești cu întrebări dacă orice parte este neclară.


Înfășurarea în sus

Și am terminat. Am aruncat o privire la un plugin incredibil de util, am trecut prin codul sursă și, în final, am terminat prin crearea unui proiect miniatural cu acesta.

Întrebări? Ce lucruri frumoase de spus? Critici? Activați secțiunea de comentarii și lasă-mă un comentariu. Vă mulțumesc foarte mult pentru lectură!

Cod