Erstellen Sie mit Knockout eine Bildergalerie

Dieser Artikel erschien zuerst in Ausgabe 228 of .net magazine - das weltweit meistverkaufte Magazin für Webdesigner und Entwickler.

Wenn Sie mit einer relativ einfachen, inhaltsbasierten Website arbeiten, muss Ihr JavaScript nicht zu kompliziert werden. Vielleicht ein Lightbox-Effekt für eine Bildergalerie und eine Formularüberprüfung. Sobald jedoch eine angemessene Datenmenge oder die Notwendigkeit, den UI-Status in Ihrer Anwendung zu verfolgen, zum Mix hinzugefügt wird, kann dies zu Problemen führen.

Bei Schnittstellen, bei denen der Benutzer Daten durchsuchen kann, ändern Sie das Erscheinungsbild oder die Position von Komponenten auf der Seite oder treffen Sie Auswahlen oder Filter, die bestehen bleiben müssen. Versuchen Sie, sich auf die DOM-Inspektion zu verlassen, um zu verstehen, wo die Dinge wahrscheinlich zu Frustration führen. Eine bessere Herangehensweise besteht möglicherweise in einer sauberen Trennung von Präsentation und Logik. Hier kommen Frameworks wie Knockout ins Spiel. Möglicherweise verwenden Sie bereits Event-Handler-Bindungen in jQuery oder anderen JavaScript-Bibliotheken, um Benutzeraktionen mit Teilen einer Seite zu verbinden Mit Knockout können wir jedoch noch einen Schritt weiter gehen und JavaScript verwenden, um die Benutzeroberfläche automatisch zu füllen. Wenn sich also die Daten oder der Status ändern, ändert sich auch die Benutzeroberfläche.

In der Rich-UI-Entwicklung kann dies das Laden und Aktualisieren von Daten erheblich vereinfachen. Es ist außerdem robuster und testbarer. Egal, ob Sie alleine oder im Team arbeiten, es ist eine großartige Möglichkeit, das Leben für alle einfacher zu machen.

Was ist Knockout?

Schlagen ist eine JavaScript-Implementierung des Model-View-View-Modellmusters, eine Möglichkeit, Daten in einem Modellobjekt zu definieren und dann DOM-Elemente oder -Vorlagen an diese Daten zu binden. Die drei Teile des Musters sind:



  • Das Model Ihre Daten: In der Regel wird JSON über Ajax geladen. Es gibt jedoch viele andere Möglichkeiten, Daten in Ihre App zu übertragen, z. B. das Abfragen eines vorhandenen DOM.
  • Die Aussicht Ihr HTML-Code mit jedem Element, das Sie füllen oder bearbeiten möchten, mit einem Datenbindung Attribut. Dies verwendet den benutzerdefinierten HTML5 Daten-* Die Attributsyntax besteht die Validierung, kann aber auch in HTML4- und XHTML-Dokumenten interpretiert werden.
  • Das Ansichtsmodell Die JavaScript-Objektinstanz, die alles miteinander verbindet. Dies sind wiederverwendbare Funktionen, sodass Sie mehrere Instanzen eines Ansichtsmodells auf einer Seite haben oder ein untergeordnetes Modell in einem übergeordneten Modell verschachteln können.

Wenn sich das Ansichtsmodell entweder durch Laden von Daten oder durch Benutzeraktion ändert, werden die entsprechenden datengebundenen DOM-Elemente automatisch aktualisiert, sodass die Benutzeroberfläche immer mit dem Ansichtsmodell synchronisiert ist. Bindungen können auch in beide Richtungen erfolgen, sodass eine Wertebindung für ein Formularelement das JavaScript-Modellobjekt bei Benutzereingaben aktualisiert und bereit ist, wieder auf dem Server gespeichert zu werden.

Knockout ist die Kreation von Steve Sanderson, der jetzt für Microsoft arbeitet und von seiner Entwickler-Community mit großartiger Online-Dokumentation gut unterstützt wird

Knockout ist die Kreation von Steve Sanderson, der jetzt für Microsoft arbeitet und von seiner Entwickler-Community mit großartiger Online-Dokumentation gut unterstützt wird

Die Dokumentation und die interaktiven Tutorials auf der Knockout-Website sind hervorragend. Anstatt sie zu wiederholen, empfehle ich Ihnen, sie sich anzusehen und durchzuarbeiten, um ein Gefühl dafür zu bekommen, was sie können. Erwähnenswert ist wahrscheinlich auch, dass die Verwendung des Datenbindung Das Attribut für Vorlagen ist nicht jedermanns Sache. Wenn Sie nicht aufpassen, kann dies dazu führen, dass eine unerwünschte Menge an JavaScript Ihr schönes, sauberes HTML verschmutzt. Es gibt jedoch Möglichkeiten, damit umzugehen, und es ist auch möglich, die Attribute programmgesteuert hinzuzufügen, wenn Sie Ihr Ansichtsmodell initialisieren.

Verwenden Sie es

Ein einfaches Beispiel für die Verwendung eines Ansichtsmodells zum Verfolgen und Aktualisieren des UI-Status ist eine Bildergalerie. Wir müssen eine Reihe von Bildern und Bildunterschriften anzeigen: Dies sind unsere Daten. Es muss auch festgelegt werden, welches das aktuell ausgewählte Bild ist, zusammen mit anderen Parametern, z. B. ob der Miniaturbildbereich links und rechts angezeigt werden soll und ob wir uns am Anfang oder Ende des Paging befinden. Dies ist der UI-Status. Es wird ein ziemlich nacktes Beispiel sein, aber ich werde erwähnen, wo es leicht erweitert werden kann.

Es gibt natürlich bereits unzählige Beispiele für diese Art von Komponenten, aber die meisten werden ihre eigene Vorstellung davon haben, wie Ihr Markup angelegt werden sollte - und es kann mühsam sein, sich in das mitgelieferte CSS zu vertiefen und Änderungen vorzunehmen. Und bevor Sie feststellen, dass das Plug-In auch 10 Dinge erledigt, die Sie nicht benötigen, trägt es zu seiner Masse und Komplexität bei. Sicherlich ist es viel besser, mit dem gewünschten HTML und Layout zu beginnen und von dort aus sauber Funktionen hinzuzufügen.

Die Online-Tutorials, in denen Knockout vorgestellt wird, sind brillante Arbeiten für sich

Die Online-Tutorials, in denen Knockout vorgestellt wird, sind brillante Arbeiten für sich

Das wichtigste Prinzip bei der Entwicklung mit einem Ansichtsmodell ist, dass es keine Kenntnisse darüber hat oder benötigt, wie das DOM strukturiert oder angeordnet ist. UI-Updates werden über Datenbindungen im HTML durchgeführt. Wenn diese vorhanden sind, funktioniert die App unabhängig davon, wie sie aussieht. Sie können beliebig viele Elemente an denselben Teil des Ansichtsmodells binden. Wenn keine Bindung hergestellt wird, treten keine negativen Auswirkungen auf, sodass Sie dieselbe Logik in vielen verschiedenen Situationen wiederverwenden können.

Das Ansichtsmodell befasst sich ausschließlich mit Daten. Durch diese lose Kopplung ist es wirklich einfach, logische, testbare Komponenten zu erstellen, die Sie nach Belieben zusammenfügen können. Knockout ist bis auf IE6 kompatibel und hängt nicht von einer anderen JavaScript-Bibliothek ab. Daher habe ich das Demo-Framework nach Möglichkeit agnostisch gehalten. Ich verwende jQuery, um das Seiten- und Ansichtsmodell zu initialisieren, aber es gibt keinen Grund, warum Sie dies nicht durch das Framework Ihrer Wahl oder durch reines JavaScript ersetzen können.

Dies ist ein großartiger Blog von Ryan Niemeyer über das Kennenlernen von Knockout und dessen Verwendung als wesentlicher Bestandteil Ihres Entwicklungs-Toolkits

Dies ist ein großartiger Blog von Ryan Niemeyer über das Kennenlernen von Knockout und dessen Verwendung als wesentlicher Bestandteil Ihres Entwicklungs-Toolkits

Einstieg

Lassen Sie uns die drei Hauptteile der Demo durcharbeiten. Das erste sind die Daten oder das Modell, die in diesem Fall aus einer Liste von Links zu Bildern in einem HTML-Dokument stammen.

Von hier aus können wir eine DOM-Abfrage verwenden, um die URL jedes Bildes und die zugehörige Beschriftung zu extrahieren und sie mit einem an das Ansichtsmodell zu liefern Initialisierung Funktion. Wir werden diese Daten in einer neuen HTML-Struktur replizieren, damit wir im Sinne einer fortschreitenden Verbesserung das ursprüngliche Markup mithilfe von JavaScript während des Ladens der Seite ausblenden können. Auf diese Weise steht die Basisbildliste weiterhin Browsern zur Verfügung, die die umfangreichere Benutzeroberfläche nicht anwenden können.

Wenn wir die Begriffe im MVVM-Musternamen der Reihe nach verwenden, wird die Ansicht als Nächstes angezeigt. Es ist jedoch sinnvoller, zuerst das Ansichtsmodell abzudecken. Dies ist der Teil, der die Daten enthält und welches Bild ausgewählt ist. Später werden wir uns auch damit befassen, was passiert, wenn der Benutzer die Auswahl ändert.

var site = site || { models: { } };site.models.Gallery = function() { var self = this; this.itemsObservables = ko.observableArray(); this.init = function(data) { ko.utils.arrayForEach(data,function(item) { self.itemsObservables.push(new site.models.GalleryItem(item)); }); }}site.models.GalleryItem = function(el) { this.isSelected = ko.observable(false); this.src = el.href; this.caption = el.innerHTML;}

Normalerweise erstelle ich einen Namespace für meinen Code. Dies verringert die Wahrscheinlichkeit von Konflikten mit anderen JavaScript-Elementen auf Ihrer Website erheblich und gibt Ihnen die Freiheit, unser Galerie-Ansichtsmodell aufzurufen Galerie ohne sich Sorgen zu machen, dass irgendwo anders eine andere „Galerie“ definiert sein könnte. Knockout erstellt auch einen eigenen Namespace. ko , der als Container für alle seine eigenen Methoden verwendet wird - ähnlich wie jQuerys $.

Die beiden folgenden Funktionen sind unsere Ansichtsmodelle, eines für die gesamte Galerie und eines für die darin enthaltenen Elemente. Wie bereits erwähnt, haben Sie die Flexibilität, untergeordnete Modelle zu verschachteln, sodass es sinnvoll ist, die Dinge in separate Blöcke aufzuteilen, wenn Sie über Funktionen verfügen, die Sie wiederholen möchten.

Innerhalb des Hauptansichtsmodells ist ein Knockout zu beobachten, itemsObservables Hier speichern wir die Daten für unsere Galerie - die Bild-URLs und Bildunterschriften. Wenn Sie es nicht als var, sondern als Variable erstellen, wird es zu einer Eigenschaft des Funktionsobjekts, sodass dieses Observable, wenn wir später eine Kopie des Ansichtsmodells instanziieren, als öffentliche Methode verfügbar ist. Dies ist wichtig, um es für die Datenbindung verfügbar zu machen . Es ist auch ein beobachtbares Array, was bedeutet, dass Knockout dies verfolgen und die Benutzeroberfläche entsprechend aktualisieren kann, wenn wir Elemente darauf verschieben oder entfernen.

Durch die Erklärung ko.observableArray Bei einem leeren Funktionsaufruf erstellen wir ihn mit 'undefinierten' Inhalten. Daher sollten wir eine Initialisierungsmethode erstellen, um Daten hinzufügen zu können. Die nächste Methode innerhalb der Funktion, this.init kümmert sich darum.

Dies ist eine Funktion, die ein Datenarray verwendet - in unserem Fall ist es das Ergebnis einer Abfrage im DOM - und innerhalb dieser Funktion wiederum als öffentliche Methode definiert ist, damit wir sie von außerhalb des Ansichtsmodells aufrufen können.

Die Patentanwaltsstelle von Secerna von Plan-B Studio verwendete Knockout, um den Status der Faltabschnitte der Navigation einfach zu verfolgen

Die Patentanwaltsstelle von Secerna von Plan-B Studio verwendete Knockout, um den Status der Faltabschnitte der Navigation einfach zu verfolgen

Der Hauptteil der Funktion verwendet eine Knockout-Dienstprogrammmethode. ko.arrayForEach , um das Datenarray zu durchlaufen und jedes Element auf zu schieben itemsObservables . Sie könnten auch verwenden $ .each in jQuery oder _.jeder in Unterstrich - oder eine andere Methode, die Sie mögen. Natürlich, sobald wir drin sind arrayForEach Rückruf hat es seine eigene Dies Daher haben wir im Ansichtsmodell selbst eine Variable selbst erstellt, um die Referenz übergeben zu können.

ko.utils.arrayForEach(data,function(item) { self.itemsObservables.push(new site.models.GalleryItem(item));});

Anstatt nur das Element selbst zu verschieben, das ein DOM-Element sein wird, erstellen wir eine Instanz des zweiten Ansichtsmodells. GalleryItem Hier werden die Eigenschaften und Observablen für einzelne Elemente in der Galerie gespeichert. Dies zeigt den Vorteil der Aufteilung unseres Ansichtsmodells in kleinere Blöcke, da wir dieses untergeordnete Ansichtsmodell beliebig oft instanziieren können.

site.models.GalleryItem = function(el) { this.isSelected = ko.observable(false); this.src = el.href; this.caption = el.innerHTML;}

Zuerst erstellen wir ein einzelnes beobachtbares Knockout ist ausgewählt Dies ist offensichtlich, ob dieses Element ausgewählt ist oder nicht. Anstatt es mit einem leeren Funktionsaufruf 'undefiniert' zu machen, wird es standardmäßig auf 'false' gesetzt, indem der Wert beim Erstellen des Observablen übergeben wird.

Dann (und hier verlassen wir uns darauf, dass ein Element übergeben wird, aber Sie können bei Bedarf auf andere testen) setzen wir this.src zu den Elementen href Attribut und this.caption zu seinem innerHTML . Dies sind eher einfache Variablen als beobachtbare Variablen, da wir nicht erwarten, dass sie sich ändern, und daher nicht den Aufwand benötigen, sie in der beobachtbaren Kette von Knockout zu halten. Der Grund dafür ist, dass wir die Daten aus dem Element extrahieren und in einem abstrakten Objekt speichern, damit wir sie nach Belieben erneut anwenden können.

Grundsätzlich ist dies alles, was wir in unseren Ansichtsmodellen benötigen, um eine einfache Galerie zu erstellen. Schauen wir uns nun die HTML-Vorlage für die Benutzeroberfläche oder die Ansicht an, in der wir die Observablen datenbinden:

Sie können sehen, dass wir ein Containerelement eingerichtet haben, ein div mit der Klasse Galerie und darin ist eine Vorlage, div.item . In früheren Versionen von Knockout mussten Sie diese Vorlagen in Skriptelemente einbetten, was aus Sicht von sauberem HTML nicht sehr zufriedenstellend war. In der aktuellen Version 2.0 ist dies jedoch nicht mehr erforderlich. Wenn Sie möchten, können Sie sogar Containerelemente entfernen, indem Sie Kontrollflussbindungen in speziell formatierten HTML-Kommentaren verwenden. Dies wird hier jedoch nicht behandelt.

Auf dem Container befindet sich ein Datenbindung Attribut mit einem Wert von foreach: itemsObservables Dies weist Knockout an, dieses beobachtbare Array zu durchlaufen und die Vorlage auf alle darin enthaltenen Elemente anzuwenden. Die Elemente sind die Instanzen der GalleryItem Ansichtsmodell, das wir in der Init-Funktion erstellt haben, damit die Datenbindung für das Bildelement in der Vorlage auf das zugreifen kann src und Bildbeschriftung Werte in jedem und setzen die Elementattribute entsprechend.

Da das beobachtbare Array leer ist, bevor wir das aufrufen drin Methode, an diesem Punkt wird es keine geben div.item Elemente im DOM - die leere Vorlage wird einfach gespeichert. Wenn wir anfangen, Elemente zum Array hinzuzufügen oder daraus zu entfernen, werden durch die Datenbindung automatisch Kopien dieser Vorlagenelemente erstellt oder zerstört.

Der letzte Schritt, damit all dies funktioniert, besteht darin, eine Instanz von zu erstellen Galerie Zeigen Sie das Modell beim Laden der Seite an und füllen Sie es mit unserem DOM-Elementarray. Ich verwende jQuery in einer bereitstehenden Funktion dafür, kann jedoch Ihre Bibliothek und die Technik Ihrer Wahl ersetzen:

$(function() { var viewModel = new site.models.Gallery(); viewModel.init($('ul.origin a')); ko.applyBindings(viewModel);});

Hier erstellen wir eine Variable viewModel Dies ist eine neue Kopie des Modells der Galerieansicht. Rufen Sie dann das auf drin Methode, die das Ergebnis einer DOM-Abfrage für alle Links in unserer Elementliste übergibt. Schließlich verwenden wir eine Knockout-Methode, um die Daten im Ansichtsmodell auf alle Bindungen in unseren Vorlagen anzuwenden. Standardmäßig gilt dies für die Körper Sie können jedoch ein zusätzliches Argument übergeben, das auf eine beliebige Stelle im Seiten-DOM abzielt, um den Umfang der Bindungen einzuschränken, z. B. wenn Sie mehrere unabhängige Ansichtsmodelle auf einer Seite wünschen. Sobald dies erledigt ist, werden alle Änderungen am Ansichtsmodell sofort in der Benutzeroberfläche angezeigt und umgekehrt.

Prototyping für ein neues Online-Spiel mit Red Badger. Mit Knockout wurde die Benutzerauswahl sofort auf einen benutzerdefinierten Fußballstreifen angewendet, der mit CSS3-Effekten erweitert wurde

Prototyping für ein neues Online-Spiel mit Red Badger. Mit Knockout wurde die Benutzerauswahl sofort auf einen benutzerdefinierten Fußballstreifen angewendet, der mit CSS3-Effekten erweitert wurde

Weitermachen

Zu diesem Zeitpunkt haben Sie eine funktionierende MVVM-Anwendung. Wenn Sie sie jedoch in einem Browser anzeigen, wird hervorgehoben, dass sie nicht sehr galerieähnlich ist, da die Vorlage lediglich die Elemente durchläuft und ihre Bilder nacheinander anzeigt. Wir brauchen noch eine Möglichkeit für den Benutzer, um zu sehen, welches Bild in der Liste ausgewählt ist, und um die Auswahl zu ändern und vor allem, um jeweils nur ein Hauptbild anzuzeigen!

Um den ersten Teil davon zu erreichen, verwenden wir das Prinzip, dass dieselben Daten mehrmals im DOM gebunden werden können, und richten eine neue Vorlage für einen Miniaturbildstreifen ein:

Wir erstellen dies mit derselben foreach Knockout-Bindung, um so viele Listenelemente anzuzeigen, wie Elemente im beobachtbaren Array vorhanden sind. Wir geben auch das gleiche Bild aus src und wieder Untertitel, jedoch in einem anderen Markup-Muster, was die Flexibilität des Ansichtsmodellansatzes zeigt. (Ich verwende zur Vereinfachung eine gequetschte Version des Hauptbilds als Miniaturbild, aber ich würde erwarten, dass eine Produktionsstätte Miniaturbilder in der richtigen Größe hat.)

Die erste Bindung für das Listenelement der Miniaturansicht lautet css: {'selected': isSelected} , die zum bedingten Anwenden einer CSS-Klasse verwendet wird - sie wird nur auf dem Element angezeigt, wenn ist ausgewählt ist wahr und gibt so das aktuell ausgewählte Element an. Als wir das erstellt haben GalleryItem Ansichtsmodell Wir haben dieses Observable standardmäßig auf false gesetzt, daher wird die Klasse vorerst nicht angewendet. Das CSS Bindung hat einen leicht kontraintuitiven Namen - es handelt sich um Klassen - aber wenn Sie einzelne CSS-Eigenschaften binden möchten, können Sie auch die verwenden Stil Bindung.

Um dies nützlich zu machen, gibt es auch ein neues Konzept für das Listenelement. eine Bindung an $ parent.select auf das Klickereignis. Wenn Sie Knockout für die Ereignisbehandlung verwenden, hat es Vorrang vor dem Standard-DOM-Ereignis und allen anderen Ereignis-Listenern, die sich möglicherweise in diesem Element befinden. Sie können die Steuerung jedoch später an sie zurückgeben, wenn Sie true von der von uns bereitgestellten Funktion zurückgeben müssen sind im Begriff zu erstellen.

Das $ parent Das Präfix der Funktionszuweisung ist vorhanden, da wir uns in der Elementvorlage im Kontext des GalleryItem Modell anzeigen, und mit diesem können wir auf seine zugreifen Elternteil Ansichtsmodell, die Instanz von Galerie und rufen Sie eine Funktion auf wählen - was wir dort definieren werden. Es könnte in die gehen GalleryItem Modell anzeigen und direkt aufgerufen werden ( using data-bind = 'click: select' ), aber dies würde bedeuten, mit jedem Element eine Kopie davon zu erstellen, und es ist ein weiterer Vorteil, wenn Sie es auch auf eine höhere Ebene bringen.

this.select = function(data,e) { self.setSelected(newSelection); e.preventDefault();}this.setSelected = function(newSelection) { ko.utils.arrayForEach(self.itemsObservables(),function(item) { item.isSelected(item == newSelection); });}

Eigentlich gibt es hier zwei neue Funktionen - wählen , das das Klickereignis behandelt und dann aufruft setSelected , was eigentlich die Auswahl trifft. Es ist nicht unbedingt erforderlich, die Dinge auf diese Weise aufzuteilen, sondern eine separate zu erstellen setSelected Methode können wir es unabhängig testen, ohne ein DOM-Ereignis simulieren zu müssen.

Die Ereignisbindungen von Knockout bieten zwei Standardargumente. Der erste, Daten ist eine Momentaufnahme dessen, was die Ziel Element ist gebunden an; in diesem Fall die relevante Instanz der GalleryItem Modell anzeigen. Der Zweite, ist ist das ursprüngliche DOM-Ereignis. Unsere Funktion ruft auf setSelected damit und verhindert die Standardaktion. Da wir in unserem Beispiel auf ein Listenelement geklickt haben, gibt es keine Standardaktion. Dies ist also nicht unbedingt erforderlich. Wenn wir jedoch die Vorlage ändern, um einen Link zu verwenden, werden wir nicht überrascht.

Wir könnten einfach einstellen ist ausgewählt auf die neue Auswahl zu wahr Dies aktualisiert die Benutzeroberfläche sofort - aber jede vorherige Auswahl wäre weiterhin aktiv. Wenn wir unsere Benutzeroberfläche so einschränken möchten, dass jeweils nur ein Hauptbild angezeigt wird und auch eine Anzeige im Miniaturbildstreifen angezeigt wird, ist dies ein Problem.

Um dies zu verhindern, durchlaufen wir alle Instanzen von GalleryItem in dem itemsObservable und vergleichen Sie sie mit der neuen Auswahl. Das Ergebnis dieses Vergleichs ist ein Boolescher Wert - falsch oder wahr -, sodass wir ihn direkt zuweisen können ist ausgewählt indem man das Observable mit dem Vergleich als Argument aufruft. Auf diese Weise kann jeweils nur eine Auswahl getroffen werden, und zwar das Element, das vorhanden ist ist ausgewählt einstellen wahr wird jetzt die CSS-Klasse erhalten ausgewählt angewendet. Hier liegt auch der Vorteil, die Auswahllogik in den Vordergrund zu stellen Galerie Das Ansichtsmodell wird klar, da wir von dieser Ebene aus problemlos auf eigene Eigenschaften zugreifen können - einschließlich aller Elemente in itemsObservables .

Die endgültige Verwendung für ist ausgewählt dient dazu, die Sichtbarkeit der Hauptbilder bedingt einzustellen.

...

Wir können dies tun, indem wir a hinzufügen sichtbar Bindend an ist ausgewählt auf div.item . Dies funktioniert durch direkte Manipulation des Stils des Elements, also jedes Element wo ist ausgewählt Bei false wird die CSS-Anzeigeregel auf gesetzt keiner Wenn sich das Ansichtsmodell ändert, ändert sich auch die Sichtbarkeit der Elemente.

Wenn wir im Browser anzeigen, sind die Dinge nicht ganz so, wie wir es von einer Galerie erwarten würden. Normalerweise wird standardmäßig das erste Bild im Set ausgewählt, aber derzeit initialisieren wir alle Elemente, die vorhanden sein sollen ist ausgewählt einstellen falsch Daher sind keine großen Bilder sichtbar, bis der Benutzer eines auswählt. Um dies zu umgehen, legen wir in der Hauptansicht die Init-Methode für das Modell fest ist ausgewählt auf den ersten Punkt zu wahr so wird es angezeigt.

this.init = function(data) { var self = this; ... this.itemsObservables()[0].isSelected(true);}

Verwenden Sie auch die internen Methoden von Knockout (z drücken , das ist eher sein eigenes als das reine JavaScript drücken ) auf der itemsObservables Array können wir es auch mit nennen () und dann auf eines seiner Elemente zugreifen, genau wie auf ein reguläres Array. Wir weisen regulären Observablen Werte zu, indem wir sie mit dem Wert als Argument aufrufen, also der neuen Zeile in der drin Funktion setzt jetzt ist ausgewählt im ersten Element im beobachtbaren Array zu wahr .

Das Einrichten und Blättern in der Bildergalerie in diesem Tutorial ist ein ziemlich einfacher Vorgang

Das Einrichten und Blättern in der Bildergalerie in diesem Tutorial ist ein ziemlich einfacher Vorgang

Fit machen

Inzwischen haben wir eine minimale, aber funktionale Bildergalerie. Es wird jeweils nur ein Bild aus einem Satz angezeigt. Außerdem werden Miniaturansichten angezeigt, auf die der Benutzer klicken kann, um auszuwählen, welches angezeigt wird.

Sie werden jedoch feststellen, dass die Hauptbilder auf eingestellt sind 800px breit, der Miniaturbildstreifen läuft über diese Breite - oder kann je nach Größe des Browsers sogar umbrochen werden. Es wäre besser, wenn wir die Breite des Streifens auf die Bildgröße beschränken und ihn je nach Auswahlort nach links oder rechts scrollen lassen könnten. Natürlich ist die 800px ist eine beliebige Zahl für diese Demo. Es kann jede Größe haben oder sogar reagieren, aber mit dieser Art von Situation kommt Knockout wirklich zur Geltung.

Um dieses Verhalten zur Benutzeroberfläche hinzuzufügen, sind eine Reihe neuer Observablen erforderlich. Daher erstellen wir ein völlig neues Ansichtsmodell. ScrollableArea , um sie zu speichern und zu verfolgen - und verschachteln Sie dies in unserem Hauptansichtsmodell, wenn wir das definieren.

site.models.Gallery = function() { var self = this; this.itemsObservables = ko.observableArray(); this.measureContent = null; this.scrollable = new site.models.ScrollableArea(); ...}

Hier gibt es noch eine neue Immobilie zu erwähnen: MeasureContent . Sie werden sehen, dass es auf null gesetzt ist und im Grunde genommen ein Platzhalter für eine Funktion ist, die wir in unserem dokumentenfertigen Code definieren, sodass wir einige jQuery-Funktionen nutzen können, ohne sie in unserem Framework-unabhängigen Ansichtsmodell zu verknüpfen. Alles andere, was mit unserer erweiterten Funktionalität zu tun hat, wird in der ScrollableArea Modell anzeigen.

site.models.ScrollableArea = function() { var self = this; this.scrollThreshold = ko.observable(0); this.contentSize = ko.observable(0); this.scrollValue = ko.observable(0); this.scrollClickStep = ko.observable(400); this.isScrollable = ko.computed(function () { return self.contentSize() > self.scrollThreshold(); });}

Der erste Teil der Observablen hier verfolgt den Status der Benutzeroberfläche. scrollThreshold ist die Gesamtbreite der Bildergalerie. In der Praxis wird dies sein 800 Dies ist jedoch ein generisches Ansichtsmodell, daher werden wir es initialisieren 0 ;; Die tatsächliche Größe kann während der übergeben werden Dokument Bereit-Funktion. contentSize wird erneut auf initialisiert 0 Dies ist ein Maß für die Gesamtbreite aller Miniaturansichten. Später werden wir diese Werte vergleichen, um festzustellen, ob der Miniaturbildbereich gescrollt werden soll oder nicht.

Der nächste ist scrollValue Dies ist eine Aufzeichnung darüber, wo sich die „linke“ Position des Miniaturbildstreifens befinden sollte, und der Standardwert ist erneut 0. Schließlich scrollClickStep ist eine Einstellung dafür, um wie viel der Miniaturbildstreifen verschoben werden soll, wenn wir nach links oder rechts gehen, und für unsere Demo ist dies standardmäßig so 400 (Pixel).

Danach gehen wir weiter zu den cleveren Sachen, wo die Kraft von Knockout wirklich offensichtlich wird. Bisher haben wir uns damit befasst ko.observable und ko.observableArray , aber es gibt eine dritte Art von beobachtbaren, ko.computed , die eine beliebige Anzahl anderer Observablen beobachten kann und einen darauf basierenden berechneten Wert zurückgibt, wenn sich eines von ihnen ändert. Dies können entweder schreibgeschützte Berechnungen oder Zwei-Wege-Lese- / Schreibfunktionen sein.

Anstatt zu schaffen isScrollable Mit einem einfachen Wert rufen wir ihn stattdessen mit einer Funktion auf, die in diesem Fall einen Vergleich von zwei unserer vorherigen Observablen zurückgibt. contentSize und scrollThreshold , um herauszufinden, ob die Gesamtbreite des Miniaturbildstreifens größer ist als der Platz, in dem wir ihn anzeigen können. Zum Zeitpunkt der Initialisierung sind beide Werte 0 Es wird also falsch sein - nicht scrollbar - aber sobald wir das DOM messen und einige reale Werte eingeben, wird es automatisch neu berechnet und alles in der Vorlage, das an dieses berechnete Observable gebunden ist, wird reagieren. Der praktische Weg dazu besteht darin, die Dokumentbereitschaftsfunktion zu erweitern, die wir bereits zum Einrichten der Hauptinstanzmodellinstanz verwenden:

$(function() { var viewModel = new site.models.Gallery(); viewModel.init($('ul.origin a')); ko.applyBindings(viewModel,$('body').get(0)); var c = $('div.controller'); viewModel.measureContent = function() { return c.find('li').width() * c.find('li').length; } viewModel.scrollable.contentSize(viewModel.measureContent()); viewModel.scrollable.scrollThreshold(c.width());});

Jetzt haben wir eine Variable hinzugefügt c , die eine DOM-Abfrage für das Element zwischenspeichert, das unsere Liste mit Miniaturansichten enthält. Die Funktion viewModel.measureContent (Denken Sie daran, dass wir dies als Nullfunktion auf dem erstellt haben Galerie Modell früher anzeigen) ist jetzt so definiert, dass einfach die Pixelbreite des ersten Listenelements in der Steuerung multipliziert mit der Anzahl der Elemente zurückgegeben wird, um die Gesamtgröße des Streifens zu erhalten. Es ist riskant, sich darauf zu verlassen, dass alle Elemente die gleiche Breite haben, aber für diese Demo ist dies ausreichend.

Huddle wechselt in naher Zukunft zu einer Knockout-basierten Anwendung auf Client-Seite

Huddle wechselt in naher Zukunft zu einer Knockout-basierten Anwendung auf Client-Seite

Diese Funktion wird verwendet, um den Wert des Observablen einzustellen scrollbar. scrollThreshold . Beachten Sie, dass wir Werte direkt in eine verschachtelte Ebene des Ansichtsmodells setzen können, da die Instanz von ScrollableArea wurde als öffentliche Methode definiert und ihre Observablen sind auch öffentlich. Wir setzen auch scrollbar. scrollThreshold auf die Breite des Containers selbst. Es ist wichtig, diese Werte festzulegen, nachdem die Bindungen des Ansichtsmodells auf das DOM angewendet wurden, um sicherzustellen, dass das vollständig gerenderte Ergebnis gemessen wird und keine leeren Vorlagen.

Das Ändern des Werts einer dieser Observablen verursacht die isScrollable beobachtbar, um neu berechnet zu werden, und wenn die Inhaltsgröße jetzt größer ist als der verfügbare Speicherplatz, wird dies wahr.

    ...
« »

Gebrauch machen von isScrollable In der Benutzeroberfläche ändern wir auch die Vorlage für Miniaturansichten. Sie werden sehen, dass es eine gibt Stil Bindung an die Liste, um ihre Breite auf unsere vorherige Berechnung einzustellen; Dies soll sicherstellen, dass das Ganze in einer Zeile angeordnet ist, obwohl die Container Element wird auf eine Breite mit beschränkt Überlauf versteckt angewendet. Der Rest der Artikelvorlage ist derselbe wie zuvor, wir haben jedoch auch zwei hinzugefügt Taste Elemente, die beide a haben sichtbar Bindend an isScrollable . Sie können wahrscheinlich herausfinden, welchen Effekt dies hat; Die Schaltflächen werden so eingestellt, dass sie angezeigt werden: Keine, bis isScrollable wahr wird. An diesem Punkt werden sie automatisch angezeigt.

Es gibt auch eine aktivieren Bindung an diese Tasten. Ich werde nicht auf die Details der berechneten Observablen eingehen, die berechnen, ob sie wahr oder falsch sind, aber sie enthalten die Logik, die die aktuelle Bildlaufposition mit den potenziellen Maximal- und Minimalwerten vergleicht und den Benutzer daran hindert, am linken Ende nach links zu scrollen des Miniaturbildstreifens und umgekehrt.

Schließlich haben die Tasten auch eine klicken Bindung an eine Funktion scrollContent, die den Bildlaufschrittbetrag abhängig von der angeklickten Richtung zum aktuellen Bildlaufwert addiert oder von diesem subtrahiert. Dies setzt letztendlich eine andere berechnete beobachtbare auf die ScrollableArea Modell anzeigen, berechneScrollValue .

this.calculatedScrollValue = ko.computed({ read: function () { return (self.isScrollable()) ? self.scrollValue() : 0; }, write: function (value) { self.scrollValue(value); }});

Hier ist ein Beispiel für eine bidirektional berechnete Observable, die Rückruffunktionen zum Lesen und Schreiben von Werten enthält. In dem lesen Funktion reagiert es auf Änderungen an isScrollable , aber wenn wir es mit einem Wert im Argument nennen, dann die schreiben Funktion wird zum Setzen ausgelöst scrollValue , die wir in einem verwenden können Stil Bindung an die Vorlage, um den Miniaturbildstreifen zu positionieren.

Einpacken

In dieser Demo wurden sehr viele Konzepte schnell eingeführt, und es wäre Ihnen verziehen, wenn einige von ihnen mehr zur Verwirrung als zur Beleuchtung beigetragen hätten. Hoffentlich haben Sie einige der Vorteile der Verwendung eines MVVM-Musters erkannt und möchten sich gerne weiter darüber informieren. Wie eingangs erwähnt, sind die Dokumentationen und Tutorials auf der Knockout-Website fantastisch und es lohnt sich, sie durchzuarbeiten.

Es gibt auch eine ganze Menge mehr Tiefe, einschließlich angepasster Bindungen, die direkt in jQuery oder die Effektmethoden anderer Bibliotheken eingebunden werden können. Also eher als eine einfache sichtbar Bindung können Sie Ihre eigenen definieren fadeVisible Elemente mit etwas mehr Stil erscheinen und verschwinden zu lassen, als nur ein- oder auszublenden oder anzuzeigen.

Das Wichtigste ist, dass wir bei allem, was beschrieben wird, eine saubere Trennung von Benutzeroberfläche und Logik anstreben. So konnten wir die Ansicht vollständig ersetzen, solange die Bindungen übertragen wurden, und alles würde noch funktionieren.

Es gibt natürlich unzählige, wesentlich funktionsreichere Galerie-Plug-Ins für jedes JavaScript-Framework, das Sie erwähnen möchten. Dies ist jedoch nur der Ausgangspunkt unserer Knockout-basierten Galerie. Für mich besteht der Vorteil darin, dass Sie einen kompakten, aber erweiterbaren Controller in Form des Ansichtsmodells erhalten, der auf jede Benutzeroberfläche angewendet werden kann ohne sich Gedanken darüber machen zu müssen, wie gut es mit Ihrer vorhandenen Seite abgespielt wird.

Dies ist eine überarbeitete, erweiterte Version eines Artikels, der erstmals unter veröffentlicht wurde 12devsofxmas.co.uk

Entdecken 101 CSS- und JavaScript-Tutorials um deine Fähigkeiten zu verbessern Kreativer Blog .