Bygg ett bildgalleri med Knockout

Författare: Lewis Jackson
Skapelsedatum: 6 Maj 2021
Uppdatera Datum: 15 Maj 2024
Anonim
Bygg ett bildgalleri med Knockout - Kreativ
Bygg ett bildgalleri med Knockout - Kreativ

Innehåll

Den här artikeln publicerades först i nummer 228 av tidningen .net - världens bästsäljande tidning för webbdesigners och utvecklare.

Om du arbetar med en ganska enkel innehållsbaserad webbplats behöver JavaScript inte bli för komplicerat. kanske en ljusboxeffekt för ett bildgalleri och någon formvalidering. Men så snart en rimlig mängd data eller behovet av att hålla reda på användargränssnittet i din applikation läggs till blandningen kan det börja orsaka lite problem.

För gränssnitt där användaren kan bläddra igenom data, ändra utseendet eller placeringen av komponenter på sidan eller göra val eller filter som behöver bestå, och försöka förlita sig på DOM-inspektion för att förstå var saker är troligen kommer att sluta i frustration. Ett bättre sätt att närma sig saker är kanske att ha en ren åtskillnad mellan presentation och logik, och det är där ramar som Knockout kommer in. Du kanske redan använder bindningar för händelsehanterare i jQuery eller andra JavaScript-bibliotek för att ansluta användaråtgärder med delar av en sida , men med Knockout kan vi gå ett steg längre och använda JavaScript för att automatiskt fylla i gränssnittet - så när data eller tillstånd ändras så gör gränssnittet också.

I rikt UI-utveckling kan detta förenkla processen för laddning och uppdatering av data. Det är också mer robust och testbart, så oavsett om du arbetar ensam eller i team är det ett utmärkt sätt att göra livet enklare för alla.


Vad är knockout?

Knockout är en JavaScript-implementering av Model-View-View Model-mönstret, ett sätt att definiera data i ett modellobjekt och sedan binda DOM-element eller mallar till den informationen. De tre delarna av mönstret är:

  • Modellen Dina data: detta laddas vanligtvis JSON via Ajax, men det finns många andra sätt att få in data i din app, till exempel att fråga en befintlig DOM.
  • Vyn Din HTML, med vilket element du vill fylla i eller manipulera, ges en data-bind attribut. Detta använder HTML5-anpassningen data-* attributssyntax, så det passerar validering men kan också tolkas i HTML4- och XHTML-dokument.
  • Utsiktsmodellen JavaScript-objektinstansen som ansluter allt tillsammans. Det här är återanvändningsfunktioner, så du kan ha flera instanser av en visningsmodell på en sida eller bo en underordnad modell i en förälder.

När visningsmodellen ändras, antingen genom en dataladdning eller användaråtgärd, uppdateras lämpliga databundna DOM-element automatiskt så att användargränssnittet alltid är synkroniserat med visningsmodellen. Bindningar kan också vara tvåvägs, så ett värde som binder till ett formulärelement uppdaterar JavaScript-modellobjektet på användarinmatningen, redo att sparas tillbaka till servern.


Dokumentationen och de interaktiva handledningarna på Knockout-webbplatsen är fantastiska, så istället för att upprepa dem rekommenderar jag att du tittar igenom och arbetar igenom dem för att få en känsla för vad den kan göra. Det är förmodligen värt att också nämna att användningen av data-bind attribut för mallar är inte för allas smak, och om du inte är försiktig kan det leda till en oönskad mängd JavaScript som förorenar din fina rena HTML. Men det finns sätt att hantera detta, och det är också möjligt att lägga till attributen programmatiskt när du initialiserar din visningsmodell.

Att använda den

Ett enkelt exempel på att använda en visningsmodell för att spåra och uppdatera UI-tillstånd är ett bildgalleri. Vi har en uppsättning bilder och bildtexter att visa: det här är våra data. Det finns också ett behov av att ställa in vilken bild som är vald för närvarande, tillsammans med andra parametrar, till exempel om miniatyrområdet ska visas åt vänster och höger och om vi är i början eller slutet av sökningen, och detta är UI-tillståndet. Det kommer att vara ett ganska nakent exempel, men jag kommer att nämna var det lätt kan förlängas.

Det finns naturligtvis otaliga exempel på den här typen av komponenter redan där, men de flesta kommer med sin egen uppfattning om hur din markering ska läggas ut - och att gräva i den medföljande CSS och börja göra ändringar kan vara ett jobb. Och det är innan du upptäcker att plugin-programmet också gör tio saker du inte behöver, vilket ökar dess volym och komplexitet. Visst är ett mycket bättre sätt att börja med den HTML och layout som du vill ha och helt enkelt lägga till funktionalitet därifrån.


Huvudprincipen att komma ihåg när man utvecklar med en visningsmodell är att den inte har eller behöver kunskap om hur DOM är strukturerad eller utformad. UI-uppdateringar hanteras genom databindningar i HTML; om dessa är närvarande kommer appen att fungera oavsett hur den ser ut. Du kan binda så många element som du vill till samma del av visningsmodellen, och om en bindning inte görs finns det inga negativa effekter så att du kan återanvända samma logik i många olika situationer.

View-modellen handlar rent data, och den här lösa kopplingen gör att det är väldigt enkelt att bygga logiska, testbara komponenter som du kan passa ihop hur du än vill. Knockout är kompatibel ner till IE6 och beror inte på något annat JavaScript-bibliotek, så jag har behållit demo-ramverket-agnostiker där det är möjligt. Jag använder jQuery för att initialisera sidan och visa modellen, men det finns ingen anledning till att du inte kunde ersätta detta med ditt ramverk - eller ren JavaScript.

Komma igång

Låt oss arbeta igenom de tre huvuddelarna som utgör demo. Först är data eller modell, som i det här fallet kommer från en lista med länkar till bilder i ett HTML-dokument.

Härifrån kan vi använda en DOM-fråga för att extrahera webbadressen till varje bild och dess relaterade bildtext och leverera dem till visningsmodellen med hjälp av en initialisering fungera. Vi kommer att replikera dessa data i en ny HTML-struktur, så i andan av progressiv förbättring kan vi dölja den ursprungliga markeringen med JavaScript under sidläsning. På detta sätt kommer den grundläggande bildlistan fortfarande att vara tillgänglig för webbläsare som inte kan använda det rikare användargränssnittet.

ul> li> a href = "img / 1.webp"> Bild 1 Bildtext / a> / li> li> a href = "img / 2.webp"> Bild 2 Bildtext / a> / li> li> a href = "img / 3.webp"> Bild 3 Bildtext / a> / li> ... li> a href = "img / 8.webp"> Bild 8 Bildtext / a> / li> / ul>

Om vi ​​tar ordet i MVVM-mönstrets namn i ordning är vyn nästa, men det kommer att vara vettigare att täcka visningsmodellen först. Det här är den del som innehåller data och vilken bild som väljs, och senare behandlar vi också vad som händer om användaren ändrar valet.

var site = site || {modeller: {}}; site.models.Gallery = funktion () {var själv = detta; this.itemsObservables = ko.observableArray (); this.init = funktion (data) {ko.utils.arrayForEach (data, funktion (objekt) {self.itemsObservables.push (ny site.models.GalleryItem (artikel));}); }} site.models.GalleryItem = function (el) {this.isSelected = ko.observable (false); this.src = el.href; this.caption = el.innerHTML;}

Vanligtvis skapar jag ett namnområde för min kod; det minskar kraftigt risken för att komma i konflikt med alla andra JavaScript på din webbplats och ger således friheten att ringa vår gallerivy-modell Galleri utan att oroa sig för att det kan finnas ett annat ”galleri” definierat någon annanstans. Knockout skapar också sitt eget namnområde, ko, som används som en behållare för alla sina egna metoder - liknar jQuerys $.

De två funktionerna som följer detta är våra vymodeller, en för det övergripande galleriet och en för objekten inuti den. Som nämnts tidigare har du flexibiliteten att bygga upp barnmodeller så det är vettigt att dela upp saker i separata block när du har funktionalitet du vill upprepa.

Inuti huvudvy modellen är en Knockout observerbar, objektObservable, där vi lagrar data för vårt galleri - bildens webbadresser och bildtexter. Att skapa det på detta snarare än som en var gör det till en egenskap för funktionsobjektet, så att när vi instantierar en kopia av visningsmodellen senare kommer denna observerbara att finnas tillgänglig som en offentlig metod - detta är viktigt för att exponera den för databindning . Det är också en observerbar matris, vilket innebär att när vi trycker på eller tar bort objekt till den kan Knockout spåra detta och uppdatera användargränssnittet i enlighet med detta.

Genom att förklara ko.observableArray med ett tomt funktionsanrop skapar vi det med 'odefinierat' innehåll, så vi bör skapa en initialiseringsmetod för att kunna lägga till data till den. Nästa metod inuti funktionen, detta.init, tar hand om det.

Det här är en funktion som tar en dataarray - i vårt fall kommer det att bli resultatet av en fråga på DOM - och igen definieras den som en offentlig metod, inom detta, så att vi kan ringa den från utsiktsmodellen.

Funktionens kropp använder en Knockout-verktygsmetod, ko.arrayForEach, för att slinga igenom dataarrayen och driva varje artikel vidare till objektObservable. Du kan också använda $. varje i jQuery eller _.varje i Underscore - eller någon annan metod du gillar. Naturligtvis, när vi väl är inne i det här arrayForEach återuppringning har sin egen detta räckvidd, så i själva visningsmodellen har vi skapat ett variabelt själv för att kunna skicka referensen.

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

I stället för att bara trycka in själva artikeln, som kommer att bli ett DOM-element, skapar vi en instans av den andra vymodellen, Galleri, som innehåller egenskaper och observationer för enskilda objekt i galleriet. Detta visar fördelen med att dela vår visningsmodell i mindre block, eftersom vi kan starta den här barnvisningsmodellen så många gånger vi vill.

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

Först skapar vi en enda Knockout som kan observeras är vald vilket, som kan vara uppenbart, är huruvida detta objekt är valt eller inte. Istället för att göra det 'odefinierat' med ett tomt funktionsanrop, kommer vi som standard att det är falskt genom att skicka in värdet när vi skapar det observerbara.

Sedan (och här förlitar vi oss på att ett element skickas in, men du kan testa för andra om det behövs) ställer vi in this.src till elementets href attribut och detta. bild till dess innerHTML. Det här är enkla variabler snarare än observerbara eftersom vi inte förväntar oss att de ska förändras och därför inte behöver kostnaden för att hålla dem i Knockouts observerbara kedja. Och anledningen till att vi alls gör det här är att vi extraherar data från elementet och lagrar det i ett abstrakt objekt så att vi kan använda det igen som vi vill.

På grundnivå är det här allt vi behöver i våra visningsmodeller för att skapa ett enkelt galleri. Låt oss nu titta på HTML-mallen för användargränssnittet, eller Visa, där vi databindar dess observationer:

div data-bind = "foreach: itemsObservables"> div> img width = "800" height = "533" data-bind = "attr: {'src': src, 'alt': caption}" /> / div> / div>

Du kan se att vi har skapat ett containerelement, en div med klassen Galleri, och inom detta finns en mall, div.item. Tidigare versioner av Knockout krävde att du bäddade in dessa mallar i skriptelement, vilket ur ren HTML inte var särskilt tillfredsställande, men i den aktuella 2.0-versionen är detta inte längre nödvändigt. Om du vill kan du till och med ta bort behållarelement genom att använda kontrollflödesbindningar i speciellt formaterade HTML-kommentarer, men vi kommer inte att täcka det här.

På behållaren finns en data-bind attribut med värdet foreach: itemsObservables, som säger till Knockout att slinga igenom den observerbara matrisen och tillämpa mallen på alla objekt som finns i den. Objekten är förekomst av Galleri visa modell som vi skapade i init-funktionen, så att data som binder till bildelementet i mallen kan komma åt src och rubrik värden inuti var och en och ställ in elementattributen därefter.

Eftersom den observerbara matrisen är tom innan vi kallar i det metod, vid den punkten kommer det inte att finnas någon div.item element i DOM - den tomma mallen lagras helt enkelt. Om vi ​​börjar lägga till eller ta bort objekt i matrisen orsakar databindningen att kopior av dessa mallelement skapas eller förstörs, allt automatiskt.

Det sista steget för att göra allt detta arbete är att skapa en instans av Galleri visa modellen på sidladdning och fylla i den med vår DOM-elementmatris. Jag använder jQuery i en färdig funktion för detta, men ersätt gärna ditt bibliotek och din teknik:

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

Här skapar vi en variabel viewModel, som är en ny kopia av Gallerivisningsmodellen, och ring sedan till i det metod, skickar in resultatet av en DOM-fråga för alla länkar i vår lista över objekt. Slutligen använder vi en Knockout-metod för att tillämpa data i visningsmodellen på alla bindningar i våra mallar. Som standard gäller det för kropp element, men du kan skicka ett ytterligare argument inriktat var som helst på sidan DOM för att begränsa bindningens omfattning, till exempel om du vill ha flera oberoende visningsmodeller på en sida. När detta är klart kommer alla ändringar av visningsmodellen att återspeglas direkt i användargränssnittet och vice versa.

Gå vidare

Vid denna tidpunkt har du ett fungerande MVVM-program, men att visa det i en webbläsare skulle markera att det inte är särskilt galleriliknande, eftersom allt mallen gör är att gå igenom objekten och visa deras bilder i sekvens. Vi behöver fortfarande ett sätt för att användaren ska kunna se vilken bild i listan som väljs och ändra valet, och viktigast av allt, att bara visa en huvudbild åt gången!

För att uppnå den första delen av detta använder vi principen att samma data kan bindas i DOM flera gånger och ställer in en ny mall för en miniatyrremsa:

div> ul data-bind = "foreach: itemsObservables"> li data-bind = "css: {'selected': isSelected}, klicka på: $ parent.select"> img data-bind = "attr: {'src': src} "width =" 140 "/> span data-bind =" text: caption "> / span> / li> / ul> / div>

Vi skapar detta med samma förknippningsbindning för att visa så många listobjekt som det finns objekt i den observerbara matrisen. Vi visar också samma bild src och bildtexter igen, men i ett annat markeringsmönster som visar flexibiliteten i synsättmodellen. (Jag använder en sammanpressad version av huvudbilden som miniatyr för enkelhet, men jag förväntar mig att en produktionswebbplats har miniatyrbilder av rätt storlek.)

Den första bindningen på miniatyrlistan är css: {’Selected’: isSelected}, som används för att villkorligt tillämpa en CSS-klass - den visas bara på elementet om är vald är sant och ange det valda objektet. När vi skapade Galleri visa modell vi gjorde detta observerbart falskt som standard, så för närvarande kommer klassen inte att tillämpas. De css bindning har ett lite kontraintuitivt namn - det handlar om klasser - men om du vill binda enskilda CSS-egenskaper kan du också använda stil bindande.

För att göra detta användbart finns det ett nytt koncept på listobjektet; en bindning till $ parent.select på klickhändelsen. Om du använder Knockout för händelsehantering kommer det att ha företräde framför DOM-händelsen som standard, och även andra eventlyssnare som kan vara med på detta element, men du kan skicka tillbaka kontrollen till dem senare om du behöver genom att returnera true från funktionen vi håller på att skapa.

De $ förälder prefixet för funktionstilldelningen finns där eftersom vi i artikelmallen är i sammanhanget med Galleri visa modellen, och genom att använda denna kan vi komma åt den förälder Visa modell, förekomsten av Galleri, och ring en funktion Välj - som vi kommer att definiera där. Det kan gå i Galleri visa modell och kallas direkt (använder data-bind = "klicka: välj"), men att göra det skulle innebära att du skapar en kopia av den med varje artikel, och det finns ytterligare en fördel att också höja nivån.

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

Egentligen finns det två nya funktioner här - Välj, som hanterar klickhändelsen och sedan ringer setSelected, som faktiskt gör valet. Det är inte nödvändigt att dela upp saker på det här sättet, utan genom att skapa en separat setSelected metod kan vi testa det självständigt utan att behöva simulera en DOM-händelse.

Knockouts händelsebindningar innehåller två standardargument. Den första, data, är en ögonblicksbild av vad mål element är bundet till; i detta fall den relevanta instansen av Galleri visa modell. Den andra, e, är den ursprungliga DOM-händelsen. Vår funktion ringer setSelected med detta och förhindrar standardåtgärden. När vi klickade på ett listobjekt i vårt exempel finns det ingen standardåtgärd, så det är inte riktigt nödvändigt, men om vi ändrar mallen för att använda en länk kommer det inte att fånga oss.

Vi kunde helt enkelt ställa in är vald på det nya urvalet till Sann, som kommer att uppdatera användargränssnittet omedelbart - men alla tidigare val skulle fortfarande vara aktiva, och om vi vill begränsa vårt användargränssnitt för att visa en huvudbild åt gången och också ha en indikator i miniatyrremsan skulle det vara ett problem.

För att förhindra detta slingrar vi alla instanser av Galleri i föremål som kan observeras och jämför dem med det nya urvalet. Resultatet av denna jämförelse är en boolesk - falsk eller sann - så att vi kan tilldela den direkt till är vald genom att kalla det observerbara med jämförelsen som argument. På detta sätt kan endast ett val göras åt gången och det objekt som finns är vald satt till Sann kommer nu att få CSS-klassen vald applicerad. Det är också här fördelen med att sätta urvalslogiken i huvudsak Galleri view-modellen blir tydlig, för från denna nivå kan vi enkelt gå in i någon av dess egna egenskaper - inklusive alla artiklar i objektObservable.

Den slutliga användningen för är vald är för att villkorligt ställa in synligheten för huvudbilderna.

div data-bind = "foreach: itemsObservables"> div data-bind = "visible: isSelected"> ... / div> / div>

Vi kan göra detta genom att lägga till en synlig bindande till är vald div.item. Detta fungerar genom att direkt manipulera elementets stil, så vilket objekt som helst är vald är falsk kommer CSS-visningsregeln att vara inställd på ingen, och när visningsmodellen ändras kommer objektens synlighet att ändras.

Återigen, om vi ser i webbläsaren är det inte riktigt vad vi förväntar oss av ett galleri. Normalt väljs den första bilden i uppsättningen som standard, men som det nu är initialiserar vi alla objekt som ska ha är vald satt till falsk, så inga stora bilder är synliga förrän användaren väljer en. För att komma runt detta, låt oss ställa in initmetoden för huvudvy-modellen är vald på det första objektet till Sann så det kommer att visas.

this.init = funktion (data) {var själv = detta; ... this.itemsObservables () [0] .isSelected (true);}

Förutom att använda Knockouts interna metoder (t.ex. skjuta på, vilket är dess eget snarare än det rena JavaScript skjuta på) på objektObservable array kan vi också kalla det med () och sedan komma åt något av dess objekt precis som vi skulle göra med en vanlig grupp. Vi tilldelar värden till vanliga observerbara genom att kalla dem med värdet som argument, så den nya raden i i det funktionen ställs in nu är vald i det första objektet i den observerbara matrisen till Sann.

Gör det passande

Nu har vi ett minimalt men funktionellt bildgalleri. Endast en bild från en uppsättning visas samtidigt och det finns en miniatyrbild som användaren kan klicka på för att välja vilken som ska visas.

Du kommer dock att märka att med huvudbilderna inställda på 800px bred, överraskar miniatyrremsan den bredden - eller kan till och med lindas, beroende på webbläsarens storlek. Det vore bättre om vi kunde begränsa remsans bredd till bildstorleken och låta den rulla åt vänster eller höger beroende på var valet är. Naturligtvis, den 800px är en godtycklig figur för denna demo. Det kan vara vilken storlek som helst eller till och med lyhörd, men att hantera denna typ av situation är där Knockout verkligen kommer till sin rätt.

Ett gäng nya observationer behövs för att lägga till detta beteende i användargränssnittet, så vi skapar en helt ny visningsmodell, ScrollableArea, för att lagra och spåra dem - och häcka detta inom vår huvudvy-modell när vi definierar det.

site.models.Gallery = funktion () {var själv = detta; this.itemsObservables = ko.observableArray (); this.measureContent = null; this.scrollable = new site.models.ScrollableArea (); ...}

Det finns en annan ny fastighet här att nämna, måttInnehåll. Du ser att den är inställd på null och i grunden är en platshållare för en funktion som vi definierar i vår dokumentklara kod, så att vi kan dra nytta av vissa jQuery-funktioner utan att få den bunden i vår ram-agnostiska visningsmodell. Allt annat att göra med vår utökade funktionalitet kommer att gå i ScrollableArea visa modell.

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 ();});}

Den första biten av observerbara här håller reda på UI: s tillstånd. scrollThreshold är den totala bredden på bildgalleriet. I praktiken kommer detta att vara 800 men det här är en generisk visningsmodell så vi initialiserar den till 0; den verkliga storleken kan skickas in under dokumentera redo-funktion. contentSize initialiseras igen till 0, och detta kommer att mäta den totala bredden på alla miniatyrobjekt. Senare jämför vi dessa värden för att se om miniatyrområdet ska rulla eller inte.

Nästa är scrollValue, detta är en registrering av var den ”vänstra” positionen för miniatyrremsan ska vara och återigen som standard 0. Slutligen, scrollClickStep är en inställning för hur mycket miniatyrremsan ska flyttas av när vi går åt vänster eller höger, och för vår demo är den som standard 400 (pixlar).

Efter detta går vi vidare till de smarta grejerna, där kraften i Knockout verkligen blir uppenbar. Hittills har vi hanterat det ko.observable och ko.observableArray, men det finns en tredje typ av observerbar, ko. beräknad, som kan titta på valfritt antal andra observerbara och returnerar ett beräknat värde baserat på dem när någon av dem ändras. Dessa kan antingen vara skrivskyddade beräkningar eller tvåvägs läs- / skrivfunktioner.

Snarare än att skapa är rullningsbar med ett enkelt värde kallar vi det istället med en funktion som i detta fall returnerar en jämförelse av två av våra tidigare observationer, contentSize och scrollThreshold, för att ta reda på om miniatyrremsans totala bredd är större än det utrymme vi har för att visa den i. Vid initialiseringstid är båda dessa värden 0, så det kommer att vara falskt - inte rullbart - men så snart vi mäter DOM och lägger in några verkliga värden där kommer den automatiskt att räkna om igen och allt i mallen som är bunden till denna beräknade observerbara svarar. Det praktiska sättet till detta är att utöka den dokumentfärdiga funktion som vi redan använder för att ställa in huvudvy-modellinstansen:

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

Nu har vi lagt till en variabel c, som cachar en DOM-fråga för elementet som innehåller vår lista med miniatyrremsor. Funktionen viewModel.measureContent (kom ihåg att vi skapade detta som en null-funktion på Galleri Visa modell tidigare) definieras nu som att bara returnera pixelbredden för det första listobjektet i styrenheten multiplicerat med antalet objekt för att ge den totala storleken på remsan. Det är riskabelt att lita på att alla artiklar har samma bredd, men för denna demo kommer det att göra.

Denna funktion används för att ställa in värdet på det observerbara rullningsbar. bläddraTröskel. Observera att vi kan ställa in värden direkt på en kapslad nivå av visningsmodellen, eftersom förekomsten av ScrollableArea definierades som en offentlig metod och dess observerbara är också offentliga. Vi satte också in rullningsbar. bläddraTröskel till bredden på själva containern. Det är viktigt att ställa in dessa värden efter att vymodellbindningarna har tillämpats på DOM, för att se till att vi mäter det fullständigt återgivna resultatet snarare än tomma mallar.

Att ändra värdet på någon av dessa observerbara orsakar är rullningsbar kan observeras för att beräknas om, och om innehållsstorleken nu är bredare än det utrymme vi har tillgängligt blir det sant.

div> ul data-bind = "foreach: itemsObservables, style: {'width': scrollable.contentSize () + 'px'}"> ... / ul> button data-bind = "synlig: scrollable.isScrollable, enable : scrollable.canScrollLeft, klicka: scrollable.scrollContent "data-direction =" left ">« / button> button data-bind = "synlig: scrollable.isScrollable, aktivera: scrollable.canScrollRight, klicka: scrollable.scrollContent" data-direction = "höger"> »/ knapp> / div>

Att använda är rullningsbar i användargränssnittet ändrar vi också mallen för miniatyrremsor. Du ser att det finns en stil bindande på listan för att ställa in dess bredd till vår tidigare beräkning; detta för att se till att det hela läggs ut på en rad även om behållare element kommer att begränsas till en bredd med överflöd: dold applicerad. Resten av artikelmallen är densamma som tidigare men vi har också lagt till två knapp element, som båda har en synlig bindande till är rullningsbar. Du kan nog räkna ut vilken effekt detta har; knapparna kommer att ställas in för att visas: ingen förrän är Scrollbar blir sant, då kommer de automatiskt att visas.

Det finns också en Gör det möjligt bindning på dessa knappar. Jag kommer inte att gå in på detaljerna i de beräknade observationerna som beräknar om de är sanna eller falska, men de innehåller logiken som jämför den aktuella rullningspositionen med de potentiella maximi- och minimivärdena och hindrar användaren från att rulla åt vänster i vänstra änden av miniatyrremsan och vice versa.

Slutligen har knapparna också en klick bindning till en funktion scrollContent, som lägger till eller subtraherar rullningsstegsbeloppet till det aktuella rullningsvärdet beroende på vilken riktning du klickade på. Detta sätter slutligen en annan beräknad observerbar på ScrollableArea se modell, calculatedScrollValue.

this.calculatedScrollValue = ko.computed ({läs: funktion () {return (self.isScrollable ())? self.scrollValue (): 0;}, skriv: funktion (värde) {self.scrollValue (värde);}} );

Här är ett exempel på en tvåvägsberäknad observerbar, som innehåller återuppringningsfunktioner för både läs- och skrivvärden. I läsa funktion kommer den att reagera på ändringar av är rullningsbar, men om vi kallar det med ett värde i argumentet då skriva funktionen utlöses för att ställa in scrollValue, som vi kan använda i en stil bindning på mallen för att placera miniatyrremsan.

Avslutar

Ganska många koncept har introducerats snabbt i denna demo, och du skulle bli förlåtad om några av dem har gjort mer för att förvirra än att belysa. Men förhoppningsvis har du sett några av fördelarna med att använda ett MVVM-mönster och är angelägna om att läsa mer om det. Som vi sa i början är dokumentationen och handledningarna på Knockout-webbplatsen fantastiska och väl värda att arbeta igenom.

Det finns också en hel del mer djup, inklusive anpassade bindningar som kan anslutas direkt till jQuery eller andra biblioteks effekter. Så snarare än en enkel synlig bindande kan du definiera din egen fadeVisible att få element att visas och försvinna med lite mer stil än att bara poppa in eller ut eller visa.

Det viktigaste att komma ihåg är att vi genom allt beskrivet har syftat till att upprätthålla en ren separation av användargränssnitt och logik. Så vi kunde helt ersätta vyn så länge bindningarna överfördes och allt skulle fortfarande fungera.

Det finns naturligtvis otaliga, betydligt mer funktionsrika galleri-plugin-program där ute för alla JavaScript-ramar som du gärna vill nämna. Men det här är bara utgångspunkten för vårt Knockout-drivna galleri, och för mig är fördelen med att göra det på det här sättet att du slutar med en kompakt men ändå utdragbar styrenhet i form av visningsmodellen, som kan tillämpas på alla användargränssnitt utan att behöva oroa sig för hur snygg det kommer att spela med din befintliga sida.

Detta är en reviderad, utökad version av en artikel som först publicerades på 12devsofxmas.co.uk

Upptäck 101 CSS- och JavaScript-handledning för att öka dina färdigheter på Creative Bloq.

Rekommenderat För Dig
Hur man utformar en original sci-fi karaktär
Upptäck

Hur man utformar en original sci-fi karaktär

Jag väljer att kildra en främmande karaktär med humanoidanatomi. Det kulle vara intre ant att göra henne tydligt främmande, men ock å att för öka göra henn...
23 designers och deras fantastiska tatueringar
Upptäck

23 designers och deras fantastiska tatueringar

Oav ett om det är en ultimat hyllning till en favoritarti t verk eller motivera av något djupt per onligt, tannar många kreativa inte vid in för ta tatuering. Och det finn en ak om...
Kom igång med HDR i Photoshop
Upptäck

Kom igång med HDR i Photoshop

High Dynamic Range (HDR) -fotografering gör att fotografer kan fånga hela tonintervallet för en bild. HDR-fotografering använder ett antal parente bilder och låter dig få...