Erstellen einer unendlichen Bildlauffunktion mit der History-Web-API

In diesem Tutorial werden wir unsere History Web API-Kenntnisse verbessern. Wir werden ein UX-Muster im Web erstellen, das gleichermaßen geliebt und verabscheut wird: unendliches Scrollen.

Unbegrenztes Scrollen ist ein Schnittstellenmuster, das neue Inhalte lädt, sobald wir das Ende einer bestimmten Webseite erreichen. Durch das unendliche Scrollen kann das Engagement der Benutzer erhalten werden, wenn es nachdenklich umgesetzt wird. Einige der besten Beispiele sind auf sozialen Plattformen wie Facebook, Twitter und Pinterest.

Es ist jedoch erwähnenswert, dass wir die Dinge, die wir in unserem vorherigen Tutorial "Lovely, Smooth Page Transitions" mit der History-Web-API aufgebaut haben, um einen erheblichen Teil verbessern. In diesem Tutorial befassen wir uns mit der Scrolling-Interaktion der Benutzer, die sehr häufig vorkommen kann. Wenn wir mit unserem Code nicht vorsichtig sind, wirkt sich dies wiederum negativ auf die Leistung unserer Website aus. Stellen Sie sicher, dass Sie die vorherigen Tutorials gelesen haben, bevor Sie dieses versuchen, nur um Ihnen ein klares Bild von dem zu geben, was wir tun.

Wenn Sie jedoch von der Idee einer Herausforderung begeistert sind, legen Sie den Sicherheitsgurt an, machen Sie sich bereit und beginnen Sie!

Erstellen der Demo-Website

Unsere Website ist ein statischer Blog. Sie können es aus reinem HTML-Code erstellen oder einen statischen Site-Generator wie Jekyll, Middleman oder Hexo nutzen. Unsere Demo für dieses Tutorial sieht folgendermaßen aus:

Einfaches altes Weiß.

In Bezug auf die HTML-Struktur gibt es einige Dinge, die Ihre Aufmerksamkeit erfordern.

 
  1. Wie Sie dem obigen Code-Snippet entnehmen können, sollte der Artikel mit einer eindeutigen ID in ein HTML-Element eingeschlossen werden. Sie können eine div oder ein Sektion Element, ohne Einschränkung hinsichtlich der Benennung der Ich würde für das Element. 
  2. Außerdem müssen Sie auf dem Artikel selbst eine Daten-Artikel-ID Attribut, das das entsprechende enthält Ich würde Nummer des Artikels.

Fühlen Sie sich frei, in Bezug auf die Website-Stile auszuarbeiten; machen Sie es farbiger, ansprechender oder fügen Sie mehr Inhalt hinzu.

Laden Sie das JavaScript

Laden Sie zunächst die folgenden JavaScript-Bibliotheken auf jeder Seite Ihres Blogs in der folgenden Reihenfolge.

  • jquery.js: die Bibliothek, die wir zum Auswählen von Elementen, zum Anhängen neuer Inhalte, zum Hinzufügen neuer Klasse und zum Durchführen von AJAX-Anforderungen verwenden werden.
  • history.js: ein Polyfill was die native History-API der Browser abschneidet.

Unser Custom jQuery Plugin

Zusätzlich zu diesen beiden müssen wir unsere eigene JavaScript-Datei laden, in die wir die Skripts schreiben können, die ausgeführt werden sollen unendliches Scrollen. Der Ansatz, den wir einschlagen, besteht darin, unser JavaScript in ein jQuery-Plugin zu packen, anstatt es direkt zu schreiben, wie wir es in den vorherigen Tutorials getan haben.

Wir starten das Plugin mit jQuery Plugin Boilerplate. Dies ähnelt der HTML5-Boilerplate, da sie eine Sammlung von Vorlagen, Mustern und bewährten Methoden zum Erstellen eines jQuery-Plugins bereitstellt.

Laden Sie die Boilerplate herunter und legen Sie sie in dem Verzeichnis Ihrer Website ab, in dem sich alle JavaScript-Dateien befinden (z. B. / vermögenswerte / js /) und benennen Sie die Datei in „keepscrolling.jquery.js“ um (dieser Name wurde von Dory von Finding Nemo und ihrer berühmten Zeile „Keep Swimming“ inspiriert).

assets / js ’keepscrolling.jquery.js ├── keepscrolling.jquery.js.map └── src └── keepscrolling.jquery.js 

Das Plugin ermöglicht uns die Einführung von Flexibilität mit Optionen oder die Einstellungen.

Beobachten der jQuery-Plugin-Struktur

Das Schreiben eines jQuery-Plugins erfordert eine etwas andere Denkweise. Wir werden zuerst prüfen, wie unser jQuery-Plugin strukturiert ist, bevor wir Code hinzufügen. Wie Sie unten sehen können, habe ich den Code in vier Abschnitte unterteilt:

; (Funktion ($, window, document, undefined) "use strict"; // 1. var pluginName = "keepScrolling", Standardeinstellungen = ; // 2. function Plugin (Element, Optionen) this.element = element; this.settings = $ .extend (, Standardwerte, Optionen); this._defaults = Standardwerte; this._name = pluginName; this.init (); // 3. $ .extend (Plugin.prototype,  init: function () console.log ("Plugin initialisiert");,); // 4. $ .fn [pluginName] = Funktion (Optionen) return this.each (function () if (! $ .data (this, "plugin_" + pluginName)) $ .data (this, "plugin_" + pluginName, neues Plugin (this, Optionen));;;;;) (jQuery, window, document); 
  1. Im ersten Abschnitt des Codes geben wir unseren Plugin-Namen an, Scroll weiter, mit "camel case" gemäß den gängigen JavaScript-Namenskonventionen. Wir haben auch eine Variable, Standardeinstellungen, welches die Standardeinstellungen des Plugins enthält.
  2. Als nächstes haben wir die Hauptfunktion des Plugins, Plugin (). Diese Funktion kann mit einem „Konstruktor“ verglichen werden, der in diesem Fall das Plugin initialisiert und die Standardeinstellungen mit beliebigen Einstellungen zusammenführt, die beim Instantiieren des Plugins übergeben wurden.
  3. Im dritten Abschnitt werden wir unsere eigenen Funktionen zusammenstellen, um die unendliche Scrollfunktion zu nutzen. 
  4. Schließlich ist der vierte Abschnitt einer, der das Ganze in ein jQuery-Plugin umschließt.

Mit all diesen Einstellungen können wir nun unser JavaScript zusammenstellen. Und wir beginnen mit der Definition der Standardoptionen unseres Plugins.

Die Optionen

(Funktion ($, window, document, undefined) "use strict"; var pluginName = "keepScrolling", default = floor: null, Artikel: null, data: ;…) (jQuery, window, Dokument);

Wie Sie oben sehen können, haben wir drei Optionen festgelegt:

  • Fußboden: eine ID-Auswahl wie #Fußboden oder #Fußzeile-Wir betrachten das Ende der Website oder den Inhalt. Normalerweise wäre dies die Fußzeile der Site.
  • Artikel: eine Klassenauswahl, die den Artikel umschließt.
  • Daten: Da wir keinen Zugriff auf externe APIs haben (unsere Website ist statisch), müssen wir eine Artikeldaten-Sammlung wie Artikel-URL, ID und Titel im JSON-Format als Optionsargument übergeben.

Die Funktionen

Hier haben wir die drin(). In dieser Funktion fügen wir eine Reihe von Funktionen hinzu, die sofort während der Standortinitialisierung ausgeführt werden müssen. Zum Beispiel wählen wir die Standfläche aus.

$ .extend (Plugin.prototype, // Die 'init ()' - Funktion. init: function () this.siteFloor = $ (this.settings.floor); // Wählen Sie den Elementsatz als Website-Boden aus. ,);

Es gibt auch einige Funktionen, die wir ausführen werden draußen die Initialisierung. Wir fügen diese Funktionen hinzu, um sie zu erstellen und nach dem drin Funktion.

Die erste Gruppe von Funktionen, die wir schreiben werden, sind Funktionen, die wir verwenden, um ein "Ding" abzurufen oder zurückzugeben. alles aus einem String, einem Objekt oder einer Zahl, der in allen anderen Funktionen des Plugins wiederverwendbar ist. Dazu gehören Dinge zu:

Holen Sie sich alle Artikel auf der Seite:

/ ** * Liste der Artikel auf der Seite suchen und zurückgeben. * @return jQuery Object Liste der ausgewählten Artikel. * / getArticles: function () return $ (this.element) .find (this.settings.article); ,

Holen Sie sich die Artikeladresse. In WordPress wird dies allgemein als "Post Slug" bezeichnet..

/ ** * Gibt die Artikeladresse zurück. * @param Integer i Der Artikelindex. * @return String Die Artikeladresse, z. 'post-two.html' * / getArticleAddr: Funktion (i) var href = window.location.href; var root = href.substr (0, href.lastIndexOf ("/")); return root + "/" + this.settings.data [i] .address + ".html"; ,

Rufen Sie die nächste Artikel-ID und Adresse ab, die abgerufen werden sollen.

/ ** * Gib den "nächsten" Artikel zurück. * @return Object Die 'id' und 'url' des nächsten Artikels. * / getNextArticle: function () // Den letzten Artikel auswählen. var $ last = this.getArticles (). last (); var articlePrevURL; / ** * Dies ist eine vereinfachte Methode zur Ermittlung der Inhalts-ID. * * Hier subtrahieren wir die letzte Beitrags-ID um '1'. * Idealerweise sollten Sie einen API-Endpunkt aufrufen, beispielsweise: * https://www.techinasia.com/wp-json/techinasia/2.0/posts/329951/previous/ * / var articleID = $ last.data ( "Artikel-ID"); var articlePrevID = parseInt (articleID, 10) - 1; // Vorherige ID // Schleife in die Option 'Daten' und rufe die entsprechende Adresse ab. for (var i = this.settings.data.length - 1; i> = 0; i--) if (this.settings.data [i] .id === articlePrevID) articlePrevURL = this.getArticleAddr (i );  return id: articlePrevID, url: articlePrevURL; , 

Nachfolgend sind die Utility-Funktionen des Plugins aufgeführt. eine Funktion, die für ein bestimmtes „Ding“ verantwortlich ist. Diese schließen ein:

Eine Funktion, die angibt, ob ein Element den Darstellungsbereich betritt. Wir verwenden es hauptsächlich, um festzustellen, ob der definierte Standort „Boden“ im Ansichtsfenster sichtbar ist.

/ ** * Ermitteln Sie, ob das Zielelement sichtbar ist. * http://stackoverflow.com/q/123999/ * * @return Boolean 'true', wenn sich das Element im Ansichtsbereich befindet, und 'false', wenn nicht. * / isVisible: function () if (Zielinstanz von jQuery) Ziel = Ziel [0];  var rect = target.getBoundingClientRect (); return rect.bottom> 0 && rect.right> 0 && rect.left < ( window.innerWidth || document.documentElement.clientWidth ) && rect.top < ( window.innerHeight || document.documentElement.clientHeight ); , 

Eine Funktion, die die Ausführung einer Funktion stoppt. bekannt als entprellen. Wie bereits erwähnt, werden wir uns mit Benutzer-Scrolling-Aktivitäten befassen, die sehr häufig vorkommen. Also eine Funktion innerhalb der scrollen Das Ereignis wird nach dem Scrollen des Benutzers häufig ausgeführt, wodurch das Scrollen auf der Website träge oder verzögert wird.

Die obige Entprellungsfunktion verringert die Ausführungshäufigkeit. Es wartet die angegebene Zeit durch warten Parameter, nachdem der Benutzer den Bildlauf beendet hat, bevor die Funktion ausgeführt wird.

/ ** * Gibt eine Funktion zurück, die, solange sie weiterhin aufgerufen wird, nicht ausgelöst wird. * Die Funktion wird aufgerufen, wenn sie für N Millisekunden nicht mehr aufgerufen wird. * Wenn sofort übergeben wird, lösen Sie die Funktion an der Vorderflanke aus, anstatt das Nachlaufzeichen. * * @link https://davidwalsh.name/function-debounce * @link http://underscorejs.org/docs/underscore.html#section-83 * * @param Funktion func Funktion zum Entprellen von * @param  Integer wait Die Zeit in ms vor dem Funktionslauf * @param Boolean sofort * @return Void * / isDebounced: function (func, wait, sofort) var timeout; return function () var context = this, args = Argumente; var später = function () timeout = null; if (! unmittelbar) func.apply (context, args); ; var callNow = sofort &&! timeout; clearTimeout (Zeitüberschreitung); timeout = setTimeout (später warten); if (callNow) func.apply (context, args); ; , 

Eine Funktion, die bestimmt, ob eine Operation fortgesetzt oder abgebrochen werden soll.

/ ** * Gibt an, ob ein neuer Artikel abgerufen werden soll (oder nicht). * @return Boolean [Beschreibung] * / isProceed: function () if (articleFetching // prüft, ob gerade ein neuer Inhalt abgerufen wird. || articleEnding // prüft, ob kein Artikel mehr geladen werden soll. || this. isVisible (this.siteFloor) // prüfe ob die definierte "Etage" sichtbar ist.) return;  if (this.getNextArticle (). id <= 0 )  articleEnding = true; return;  return true; , 

Wir werden die vorstehende Dienstprogrammfunktion verwenden, isProceed (), zu prüfen, ob alle Bedingungen erfüllt sind, um neue Inhalte herauszuholen. Wenn ja, wird die Funktion ausgeführt, die den neuen Inhalt abruft und an den letzten Artikel anfügt.

/ ** * Funktion zum Abrufen und Anhängen eines neuen Artikels. * @return Void * / fetch: function () // Fortfahren oder nicht? if (! this.isProceed ()) return;  var main = this.element; var $ articleLast = this.getArticles (). last (); $ .ajax (url: this.getNextArticle (). url, Typ: "GET", Datentyp: "html", beforeSend: function () articleFetching = true;) / ** * Wenn die Anforderung abgeschlossen ist Wenn der Inhalt erfolgreich abgerufen wird *, wird der Inhalt angefügt. * / .done (function (res) $ articleLast .after (function () if (! res) return; return $ (res) .find ("#" + main.id) .html (); );) / ** * Wenn die Funktion abgeschlossen ist ("fail" oder "done"), setzen Sie * das "articleFetching" immer auf "false". * Es gibt an, dass wir den neuen Inhalt abgerufen haben. * / .always (function () articleFetching = false;); , 

Fügen Sie diese Funktion innerhalb der hinzu drin. Die Funktion wird also ausgeführt, sobald das Plugin initialisiert ist, und ruft den neuen Inhalt ab, wenn die Bedingungen erfüllt sind.

init: function () this.siteFloor = $ (this.settings.floor); // Wählen Sie den Elementsatz als Standortetage aus. this.fetch (); , 

Als Nächstes fügen wir eine Funktion zum Ändern des Browserverlaufs mit der History-Web-API hinzu. Diese spezielle Funktion ist etwas komplexer als unsere vorhergehenden Funktionen. Der knifflige Teil hier ist, wann genau wir den Verlauf während des Benutzerrollens, den Dokumenttitel und die URL ändern sollten. Die folgende Abbildung soll die Idee hinter der Funktion vereinfachen:

Wie Sie der Abbildung entnehmen können, haben wir drei Linien: "Dachlinie", "Mittellinie" und "Bodenlinie", die die Position des Artikels innerhalb des Ansichtsfensters veranschaulichen. Das Bild zeigt, dass sich der untere Teil des ersten Artikels sowie der obere Teil des zweiten Artikels jetzt in der Mittellinie befinden. Die Absicht des Benutzers hinsichtlich des Artikels, den er betrachtet, ist nicht genau festgelegt. Ist es der erste Beitrag oder ist es der zweite Beitrag? Daher würden wir den Browserverlauf nicht ändern, wenn sich zwei Artikel an dieser Position befinden.

Wir werden den Verlauf für den nachfolgenden Beitrag aufzeichnen, wenn der Artikel oben die "Dachlinie" erreicht, da er den größten Teil des sichtbaren Teils des Ansichtsfensters beansprucht.

Wir zeichnen die Geschichte des vorherigen Beitrags auf, wenn sein Boden die "Floorline" erreicht, ähnlich wie jetzt der größte Teil des sichtbaren Teils des Ansichtsfensters.

Dies ist der "while" -Code, den Sie hinzufügen müssen:

init: function () this.roofLine = Math.ceil (window.innerHeight * 0.4); // setze die Dachlinie; this.siteFloor = $ (this.settings.floor); this.fetch (); , / ** * Browserverlauf ändern. * @return Void * / history: function () if (! window.History.enabled) return;  this.getArticles () .each (Funktion (Index, Artikel) var scrollTop = $ (window) .scrollTop (); var articleOffset = Math.floor (article.offsetTop - scrollTop); if (articleOffset> this.threshold) return; var articleFloor = (article.clientHeight - (this.threshold * 1.4)); articleFloor = Math.floor (articleFloor * -1); if (articleOffset < articleFloor )  return;  var articleID = $( article ).data( "article-id" ); articleID = parseInt( articleID, 10 ); var articleIndex; for ( var i = this.settings.data.length - 1; i >= 0; i--) if (this.settings.data [i] .id === articleID) articleIndex = i;  var articleURL = this.getArticleAddr (articleIndex); if (window.location.href! == articleURL) var articleTitle = this.settings.data [articleIndex] .title; window.History.pushState (null, articleTitle, articleURL);  .bind (this)); , 

Als letztes erstellen wir eine Funktion, die das ausführen wird holen() und das Geschichte() wenn der Benutzer die Seite scrollt. Dazu erstellen wir eine neue Funktion namens Scroller (), und führen Sie es auf der Plugin-Initialisierung aus.

/ ** * Funktionen, die während des Bildlaufs ausgeführt werden. * @return Void * / scroller: function () window.addEventListener ("scroll", this.isDebounced (function () this.fetch (); this.history ();, 300) .bind (this.) ), falsch);  

Und wie Sie oben sehen können, wir entprellen Da sowohl AJAX als auch das Ändern des Browserverlaufs durchgeführt werden, ist dies ein teurer Vorgang.

Hinzufügen eines Inhaltsplatzhalters

Dies ist optional, wird jedoch empfohlen, um die Benutzererfahrung zu respektieren. Der Platzhalter gibt dem Benutzer eine Rückmeldung und signalisiert, dass ein neuer Artikel unterwegs ist.

Zuerst erstellen wir die Platzhaltervorlage. Normalerweise wird diese Art von Vorlage nach dem Fußbereich der Site eingefügt.

 

Beachten Sie, dass der Platzhalterartikel und seine Struktur dem tatsächlichen Inhalt Ihres Blogs ähneln sollten. Passen Sie die HTML-Struktur entsprechend an.

Die Platzhalterstile sind einfacher. Es umfasst alle grundlegenden Stile, um es wie der eigentliche Artikel, die Animation, darzustellen @keyframe Das simuliert den Ladesinn und den Stil zum Umschalten der Sichtbarkeit (der Platzhalter wird anfangs ausgeblendet; er wird nur angezeigt, wenn das übergeordnete Element über das Symbol verfügt abholen Klasse).

.Platzhalter Farbe: @ Graulicht; Polsterauflage: 60px; Polsterung unten: 60px; Bordüre: 6px solid @ grau-leichter; Anzeige: keine; .abruf & display: block;  p Anzeige: Block; Höhe: 20px; Hintergrund: @ Graulicht;  & __ Header Animationsverzögerung: .1s; h1 Höhe: 30px; Hintergrundfarbe: @ Graulicht;  & __ p-1 Animationsverzögerung: .2s; Breite: 80%;  & __ p-2 Animationsverzögerung: .3s; Breite: 70%;  

Anschließend aktualisieren wir einige Zeilen, um den Platzhalter während der AJAX-Anforderung anzuzeigen, wie folgt.

/ ** * Initialisieren. * @return Void * / init: function () this.roofLine = Math.ceil (window.innerHeight * 0.4); this.siteFloor = $ (this.settings.floor); this.addPlaceholder (); this.fetch (); this.scroller (); , / ** * Füge den addPlaceholder hinzu. * Platzhalter wird verwendet, um anzuzeigen, dass ein neuer Beitrag geladen wird. * @return Void * / addPlaceholder: function () var tmplPlaceholder = document.getElementById ("tmpl-Platzhalter"); tmplPlaceholder = tmplPlaceholder.innerHTML; $ (this.element) .append (tmplPlaceholder); , / ** * Funktion zum Abrufen und Anhängen eines neuen Artikels. * @return Void * / fetch: function () … // Wählen Sie das Element aus, das den Artikel umgibt. var main = this.element; $ .ajax (… beforeSend: function () … // fügt die Klasse 'fetching' hinzu. $ (main) .addClass (function () return "fetching";);)) always (function () … // Entferne die Klasse 'fetching'. $ (Main) .removeClass (function () return "fetching";););

So gehen wir mit dem Platzhalter um! Unser Plugin ist fertig und es ist an der Zeit, das Plugin bereitzustellen.

Einsatz

Die Bereitstellung des Plugins ist recht einfach. Wir bezeichnen das Element, das unseren Blogartikel einschließt, und nennen unser Plugin mit den eingestellten Optionen wie folgt.

$ (document) .ready (function () $ ("#main") .keepScrolling (floor: "#footer", Artikel: ".article") data: ["id": 1, "address": "post-one", "title": "Post one", "id": 2, "address": "post-two", "titel": "Post Two", "id": 3, "Adresse": "Post-Three", "Titel": "Post Three", "id": 4, "Adresse": "Post-Four", "Titel": "Post Four", "id ": 5," Adresse ":" Post-Five "," Titel ":" Post Five "]);); 

Die unendliche Schriftrolle sollte jetzt funktionieren.

Vorbehalt: der Zurück-Button

In diesem Lernprogramm haben wir ein unendliches Scrollerlebnis entwickelt. etwas, das wir häufig auf Nachrichtenseiten wie Quartz, TechInAsia und in vielen mobilen Anwendungen gesehen haben.

Obwohl es sich nachweislich als wirksames Mittel zur Beibehaltung des Benutzereingriffs erwiesen hat, hat es auch einen Nachteil: Es bricht die Schaltfläche "Zurück" im Browser. Wenn Sie auf die Schaltfläche klicken, blättern Sie nicht immer genau zum vorherigen besuchten Inhalt oder zur vorherigen Seite.

Websites behandeln dieses Problem auf verschiedene Weise. Quarz zum Beispiel leitet Sie zur bezeichnet URL; Die URL, die Sie zuvor besucht haben, jedoch nicht die URL, die über die Webprotokoll-API erfasst wurde. TechInAsia bringt Sie einfach zurück zur Homepage.

Einpacken

Dieses Tutorial ist lang und beinhaltet viele Dinge! Einige von ihnen sind leicht zu verstehen, während einige Stücke möglicherweise nicht so leicht zu verdauen sind. Als Hilfe zu diesem Artikel habe ich eine Liste von Referenzen zusammengestellt.

  • Browserverlauf manipulieren
  • Schöne, glatte Seitenübergänge mit der History-Web-API
  • Kann jemand das "Abspringen" erklären? Funktion in Javascript
  • AJAX für Frontend-Designer
  • jQuery Plugin-Entwicklung: Best Practices

Schauen Sie sich schließlich den vollständigen Quellcode an und sehen Sie sich die Demo an!