Zbuduj galerię obrazów za pomocą Knockout

Autor: Lewis Jackson
Data Utworzenia: 6 Móc 2021
Data Aktualizacji: 1 Czerwiec 2024
Anonim
Baal Veer - Episode 268 - 1st October 2013
Wideo: Baal Veer - Episode 268 - 1st October 2013

Zawartość

Ten artykuł pojawił się po raz pierwszy w numerze 228 magazynu .net - najlepiej sprzedającego się magazynu na świecie dla projektantów i programistów stron internetowych.

Jeśli pracujesz z dość prostą witryną internetową opartą na treści, Twój JavaScript nie musi być zbyt skomplikowany; być może efekt lightbox dla galerii obrazów i weryfikacja formularza. Ale gdy tylko odpowiednia ilość danych lub potrzeba śledzenia stanu interfejsu użytkownika w twojej aplikacji zostanie dodana do mieszanki, może zacząć powodować pewien problem.

W przypadku interfejsów, w których użytkownik może przeglądać dane, zmieniać wygląd lub położenie komponentów na stronie lub dokonywać wyborów lub filtrów, które muszą być trwałe, próbując polegać na inspekcji DOM, aby zrozumieć, gdzie może się skończyć frustracja. Być może lepszym sposobem podejścia do rzeczy jest czyste oddzielenie prezentacji i logiki. I tu właśnie pojawiają się frameworki, takie jak Knockout. Możesz już używać powiązań obsługi zdarzeń w jQuery lub innych bibliotekach JavaScript do łączenia działań użytkownika z częściami strony , ale dzięki Knockout możemy pójść o krok dalej i użyć JavaScript do automatycznego zapełnienia interfejsu - więc zawsze, gdy zmieniają się dane lub stan, zmienia się interfejs użytkownika.

W rozbudowanym interfejsie użytkownika może to znacznie uprościć proces ładowania i aktualizowania danych. Jest też bardziej wytrzymały i testowalny, więc niezależnie od tego, czy pracujesz samodzielnie, czy w zespole, jest to świetny sposób, aby ułatwić życie wszystkim.


Co to jest Knockout?

Knockout to implementacja w JavaScript wzorca Model-View-View Model, sposób definiowania danych w obiekcie modelu, a następnie wiązania elementów DOM lub szablonów z tymi danymi. Trzy części wzoru to:

  • Model Twoje dane: zazwyczaj będzie to JSON ładowany przez Ajax, ale istnieje wiele innych sposobów na pobranie danych do aplikacji, takich jak zapytanie o istniejący DOM.
  • Widok Twój kod HTML z dowolnym elementem, który chcesz wypełnić lub manipulować, biorąc pod uwagę rozszerzenie wiązanie danych atrybut. Używa niestandardowego HTML5 dane-* atrybutów, więc przechodzi walidację, ale może być również interpretowany w dokumentach HTML4 i XHTML.
  • Model widoku Instancja obiektu JavaScript, która łączy wszystko razem. Są to funkcje wielokrotnego użytku, więc możesz mieć wiele wystąpień modelu widoku na jednej stronie lub zagnieździć model podrzędny w nadrzędnym.

Za każdym razem, gdy model widoku zmienia się, czy to w wyniku ładowania danych, czy działania użytkownika, odpowiednie elementy DOM powiązane z danymi są automatycznie aktualizowane, dzięki czemu interfejs użytkownika jest zawsze zsynchronizowany z modelem widoku. Powiązania mogą być również dwukierunkowe, więc powiązanie wartości w elemencie formularza zaktualizuje obiekt modelu JavaScript po wprowadzeniu danych przez użytkownika, gotowy do zapisania z powrotem na serwerze.


Dokumentacja i interaktywne samouczki na stronie Knockout są znakomite, więc zamiast ich powtarzać, radzę przyjrzeć się im i przejrzeć je, aby poczuć, co potrafi. Prawdopodobnie warto również wspomnieć, że użycie rozszerzenia wiązanie danych atrybut tworzenia szablonów nie każdemu przypadnie do gustu, a jeśli nie będziesz ostrożny, może to doprowadzić do niepożądanej ilości kodu JavaScript zanieczyszczającego Twój ładny, czysty kod HTML. Istnieją jednak sposoby radzenia sobie z tym problemem, a także możliwe jest programowe dodawanie atrybutów podczas inicjowania modelu widoku.

Wykorzystanie go

Prostym przykładem wykorzystania modelu widoku do śledzenia i aktualizowania stanu interfejsu użytkownika jest galeria obrazów. Mamy zestaw obrazów i podpisów do wyświetlenia: to są nasze dane. Istnieje również potrzeba określenia, który obraz jest aktualnie wybrany, wraz z innymi parametrami, takimi jak czy obszar miniatur powinien być przewijany po lewej i prawej stronie oraz czy jesteśmy na początku, czy na końcu stronicowania, a to jest stan interfejsu użytkownika. Będzie to dość prosty przykład, ale wspomnę, gdzie można go łatwo rozszerzyć.

Oczywiście istnieje niezliczona ilość przykładów tego rodzaju komponentów, ale większość z nich przyjdzie z własnym pomysłem na to, jak powinien wyglądać twój znacznik - a zagłębianie się w dostarczony CSS i rozpoczęcie wprowadzania zmian może być uciążliwe. I to zanim odkryjesz, że wtyczka robi 10 rzeczy, których nie potrzebujesz, zwiększając swoją objętość i złożoność. Z pewnością znacznie lepszym sposobem jest rozpoczęcie od kodu HTML i układu, które chcesz, i dodanie stamtąd czystych funkcji.


Kluczową zasadą, o której należy pamiętać podczas tworzenia modelu widoku, jest to, że nie ma on ani nie potrzebuje wiedzy na temat struktury lub rozplanowania modelu DOM. Aktualizacje interfejsu użytkownika są obsługiwane przez powiązania danych w kodzie HTML; jeśli są obecne, aplikacja będzie działać niezależnie od tego, jak wygląda. Możesz powiązać dowolną liczbę elementów z tą samą częścią modelu widoku, a jeśli powiązanie nie zostanie utworzone, nie ma żadnych złych skutków, więc możesz ponownie użyć tej samej logiki w wielu różnych sytuacjach.

Model widoku dotyczy wyłącznie danych, a to luźne powiązanie oznacza, że ​​naprawdę łatwo jest zbudować logiczne, testowalne komponenty, które można dopasować do siebie w dowolny sposób. Knockout jest kompatybilny z IE6 i nie zależy od żadnej innej biblioteki JavaScript, więc w miarę możliwości zachowałem niezależność od frameworka demonstracyjnego. Używam jQuery do inicjalizacji strony i widoku modelu, ale nie ma powodu, dla którego nie mógłbyś zastąpić tego wybranym frameworkiem - lub czystym JavaScriptem.

Pierwsze kroki

Przyjrzyjmy się trzem głównym częściom, które składają się na wersję demonstracyjną. Pierwsza to dane lub model, który w tym przypadku pochodzi z listy linków do obrazów w dokumencie HTML.

Stąd możemy użyć zapytania DOM, aby wyodrębnić adres URL każdego obrazu i powiązany z nim podpis i dostarczyć je do modelu widoku za pomocą inicjalizacja funkcjonować. Zreplikujemy te dane w nowej strukturze HTML, więc w duchu stopniowego ulepszania możemy ukryć oryginalne znaczniki za pomocą JavaScript podczas ładowania strony. W ten sposób podstawowa lista obrazów będzie nadal dostępna dla przeglądarek, które nie mogą zastosować bogatszego interfejsu użytkownika.

ul> li> a href = "img / 1.webp"> Obraz 1 Podpis / a> / li> li> a href = "img / 2.webp"> Obraz 2 Podpis / a> / li> li> a href = "img / 3.webp"> Obraz 3 Podpis / a> / li> ... li> a href = "img / 8.webp"> Obraz 8 Podpis / a> / li> / ul>

Jeśli weźmiemy po kolei terminy w nazwie wzorca MVVM, widok jest następny, ale bardziej sensowne będzie najpierw pokrycie modelu widoku. To jest część, która przechowuje dane i który obraz jest wybrany, a później zajmiemy się również tym, co się stanie, jeśli użytkownik zmieni wybór.

var site = site || {modele: {}}; 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;}

Zwykle tworzę przestrzeń nazw dla mojego kodu; znacznie zmniejsza to ryzyko konfliktu z jakimkolwiek innym JavaScriptem w Twojej witrynie, a tym samym daje swobodę wywoływania naszego modelu widoku galerii Galeria bez obawy, że gdzieś indziej może być zdefiniowana inna „galeria”. Knockout tworzy również własną przestrzeń nazw, ko, który jest używany jako kontener dla wszystkich własnych metod - podobnie jak w jQuery $.

Dwie następujące funkcje to nasze modele widoku, jedna dla ogólnej galerii, a druga dla elementów w niej zawartych. Jak wspomniano wcześniej, masz możliwość zagnieżdżania modeli potomnych, więc jeśli masz funkcję, którą chcesz powtórzyć, sensowne jest podzielenie rzeczy na oddzielne bloki.

Wewnątrz modelu widoku głównego jest obserwowalna nokaut, itemsObservables, gdzie będziemy przechowywać dane dla naszej galerii - adresy URL obrazów i podpisy. Stworzenie go na tym, a nie jako zmienna powoduje, że jest on właściwością obiektu funkcji, więc kiedy później utworzymy instancję modelu widoku, ten obserwowalny będzie dostępny jako metoda publiczna - jest to niezbędne, aby ujawnić go do powiązania danych . Jest to również obserwowalna tablica, co oznacza, że ​​kiedy wypychamy lub usuwamy do niej elementy, Knockout może to śledzić i odpowiednio aktualizować interfejs użytkownika.

Deklarując ko.observableArray z pustym wywołaniem funkcji tworzymy ją z „niezdefiniowaną” zawartością, więc powinniśmy stworzyć metodę inicjalizacji, aby móc dodawać do niej dane. Następna metoda wewnątrz funkcji, this.init, dba o to.

To funkcja, która pobiera tablicę danych - w naszym przypadku będzie to wynik zapytania w DOM - i ponownie jest zdefiniowana jako metoda publiczna, w ramach tego, abyśmy mogli ją wywołać spoza modelu widoku.

Ciało funkcji korzysta z metody narzędzia Knockout, ko.arrayForEach, aby zapętlić tablicę danych i wypchnąć do niej każdy element itemsObservables. Możesz również użyć $ .each w jQuery lub _.każdy w Underscore - lub inną metodą, którą lubisz. Oczywiście, kiedy już się w tym znajdziemy arrayForEach wywołanie zwrotne ma swoje własne to zakres, więc w samym modelu widoku utworzyliśmy zmienną self, aby móc przekazać odniesienie.

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

Zamiast tylko wpychać sam element, który będzie elementem DOM, tworzymy instancję modelu drugiego widoku, GalleryItem, który będzie zawierał właściwości i obserwowalne dla poszczególnych elementów w galerii. Pokazuje to zaletę dzielenia naszego modelu widoku na mniejsze bloki, ponieważ możemy tworzyć instancje tego modelu widoku podrzędnego tyle razy, ile chcemy.

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

Najpierw tworzymy jeden obserwowalny Knockout jest zaznaczone co, jak może być oczywiste, zależy od tego, czy ta pozycja jest wybrana, czy nie. Zamiast określać ją jako „niezdefiniowaną” za pomocą pustego wywołania funkcji, ustawimy ją domyślnie na fałsz, przekazując wartość podczas tworzenia tego, co obserwowalne.

Następnie (i tutaj polegamy na przekazaniu elementu a, ale w razie potrzeby możesz przetestować dla innych) ustawiliśmy this.src do elementu href atrybut i this.caption do tego innerHTML. Są to raczej proste zmienne niż obserwowalne, ponieważ nie spodziewamy się, że ulegną one zmianie i dlatego nie potrzebujemy kosztów utrzymania ich w obserwowalnym łańcuchu Knockouta. A powodem, dla którego w ogóle to robimy, jest to, że wyodrębniamy dane z elementu i przechowujemy je w abstrakcyjnym obiekcie, abyśmy mogli zastosować je ponownie w dowolny sposób.

Na poziomie podstawowym to wszystko, czego potrzebujemy w naszych modelach widoków, aby stworzyć prostą galerię. Przyjrzyjmy się teraz szablonowi HTML dla interfejsu użytkownika lub widoku, w którym będziemy wiązać dane z jego obserwowalnymi:

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

Jak widać, utworzyliśmy element kontenera, element div z klasą Galeria, a w tym jest szablon, div.item. Poprzednie wersje Knockout wymagały osadzenia tych szablonów w elementach skryptu, co z punktu widzenia czystego HTML nie było zadowalające, ale w obecnej wersji 2.0 nie jest to już konieczne. Jeśli chcesz, możesz nawet usunąć elementy kontenera, używając powiązań przepływu sterowania w specjalnie sformatowanych komentarzach HTML, ale nie omówimy tego tutaj.

Na pojemniku jest wiązanie danych atrybut o wartości foreach: itemsObservables, co mówi Knockoutowi, aby przeszedł przez tę obserwowalną tablicę i zastosował szablon do wszystkich elementów w nim zawartych. Elementy są instancjami GalleryItem model widoku, który utworzyliśmy w funkcji init, więc powiązanie danych w elemencie obrazu w szablonie może uzyskać dostęp do pliku src i podpis wartości wewnątrz każdego z nich i odpowiednio ustaw atrybuty elementu.

Ponieważ obserwowalna tablica jest pusta przed wywołaniem funkcji w tym metoda, w tym momencie nie będzie div.item elementy w DOM - pusty szablon jest po prostu przechowywany. Jeśli zaczniemy dodawać lub usuwać elementy do tablicy, powiązanie danych spowoduje utworzenie lub zniszczenie kopii tych elementów szablonu, wszystko automatycznie.

Ostatnim krokiem, aby wszystkie te działania działały, jest utworzenie instancji Galeria wyświetl model podczas ładowania strony i wypełnij go naszą tablicą elementów DOM. Używam jQuery w gotowej funkcji do tego, ale możesz zastąpić swoją bibliotekę i wybraną technikę:

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

Tutaj tworzymy zmienną viewModel, który jest nową kopią modelu widoku galerii, a następnie wywołaj plik w tym przekazując wynik zapytania DOM dla wszystkich linków w ramach naszej listy elementów. Na koniec używamy metody Knockout, aby zastosować dane w modelu widoku do wszystkich powiązań w naszych szablonach. Domyślnie będzie to miało zastosowanie do ciało element, ale możesz przekazać dodatkowy argument wskazujący na dowolne miejsce w DOM strony, aby ograniczyć zakres powiązań, na przykład jeśli chcesz mieć wiele niezależnych modeli widoku na jednej stronie. Gdy to zrobisz, wszelkie zmiany w modelu widoku zostaną natychmiast odzwierciedlone w interfejsie użytkownika i odwrotnie.

Iść dalej

W tym momencie masz działającą aplikację MVVM, ale wyświetlenie jej w przeglądarce podkreśliłoby, że nie jest ona zbyt podobna do galerii, ponieważ wszystko, co robi szablon, to pętla po elementach i wyświetlanie ich obrazów po kolei. Nadal potrzebujemy sposobu, aby użytkownik mógł zobaczyć, który obraz na liście jest wybrany i zmienić zaznaczenie, a co najważniejsze, wyświetlać tylko jeden główny obraz naraz!

Aby osiągnąć pierwszą część tego, skorzystamy z zasady, że te same dane mogą być kilkakrotnie powiązane w DOM i skonfigurujemy nowy szablon dla paska miniatur:

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

Tworzymy to przy użyciu tego samego powiązania foreach Knockout, aby wyświetlić tyle elementów listy, ile jest elementów w obserwowalnej tablicy. Produkujemy również ten sam obraz src i podpisy ponownie, ale w innym wzorcu znaczników, pokazując elastyczność podejścia modelu widoku. (Dla ułatwienia używam ściśniętej wersji głównego obrazu jako miniatury, ale spodziewałbym się, że witryna produkcyjna będzie miała miniatury o odpowiedniej wielkości).

Pierwszym powiązaniem elementu listy miniatur jest css: {’Selected’: isSelected}, który służy do warunkowego zastosowania klasy CSS - pojawi się tylko w elemencie, jeśli jest zaznaczone jest prawdziwe, więc wskazuje aktualnie wybrany element. Kiedy stworzyliśmy GalleryItem model widoku domyślnie ustawiliśmy ten obserwowalny fałsz, więc na razie klasa nie zostanie zastosowana. Plik css bindowanie ma nieco sprzeczną z intuicją nazwę - zajmuje się klasami - ale jeśli chcesz powiązać poszczególne właściwości CSS, możesz również użyć styl wiążący.

Aby było to przydatne, istnieje również nowa koncepcja elementu listy; powiązanie z $ parent.select w przypadku kliknięcia. Jeśli użyjesz Knockout do obsługi zdarzeń, będzie on miał pierwszeństwo przed domyślnym zdarzeniem DOM, a także innymi odbiornikami zdarzeń, które mogą znajdować się w tym elemencie, ale możesz przekazać im kontrolę później, jeśli zajdzie taka potrzeba, zwracając wartość true z funkcji my mają zamiar stworzyć.

Plik $ rodzic prefiks przypisania funkcji istnieje, ponieważ w szablonie elementu znajdujemy się w kontekście GalleryItem zobacz model, a używając tego możemy uzyskać dostęp do jego rodzic zobacz model, wystąpienie Galeriai wywołaj funkcję Wybierz - które tam zdefiniujemy. Może wejść do GalleryItem zobacz model i zadzwoń bezpośrednio (używając data-bind = "click: select"), ale oznaczałoby to utworzenie kopii tego elementu z każdym elementem, a także podniesienie poziomu o kolejny poziom.

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

Właściwie są tutaj dwie nowe funkcje - Wybierz, który obsługuje zdarzenie kliknięcia, a następnie wywołuje setSelected, który faktycznie dokonuje wyboru. Nie jest konieczne rozdzielanie rzeczy w ten sposób, ale tworzenie oddzielnych setSelected możemy ją przetestować niezależnie, bez konieczności symulacji zdarzenia DOM.

Wiązania zdarzeń Knockout zapewniają dwa domyślne argumenty. Pierwszy, dane, jest migawką tego, co cel element jest powiązany; w tym przypadku odpowiednie wystąpienie GalleryItem zobacz model. Drugi, mi, to oryginalne zdarzenie DOM. Nasze wywołania funkcji setSelected z tym i zapobiega domyślnej akcji. Ponieważ kliknęliśmy element listy w naszym przykładzie, nie ma domyślnej akcji, więc nie jest to konieczne, ale jeśli zmienimy szablon tak, aby używał łącza, to nas nie złapie.

Moglibyśmy po prostu ustawić jest zaznaczone na nowy wybór do prawdziwe, który natychmiast zaktualizuje interfejs użytkownika - ale każdy poprzedni wybór nadal byłby aktywny, a jeśli chcemy ograniczyć nasz interfejs użytkownika do wyświetlania jednego głównego obrazu na raz, a także mieć wskaźnik na pasku miniatur, byłby to problem.

Aby temu zapobiec, przechodzimy przez wszystkie wystąpienia GalleryItem w przedmioty Obserwowalne i porównaj je z nowym wyborem. Wynikiem tego porównania jest wartość logiczna - fałsz lub prawda - więc możemy ją bezpośrednio przypisać jest zaznaczone wywołując obserwowalne z porównaniem jako argumentem. W ten sposób można dokonać tylko jednego wyboru na raz i elementu, który ma jest zaznaczone Ustawić prawdziwe otrzyma teraz klasę CSS wybrany stosowany. Jest to również korzyść z umieszczenia logiki wyboru w głównym Galeria model widoku staje się jasny, ponieważ z tego poziomu możemy łatwo wejść do dowolnej z jego właściwości - w tym do wszystkich pozycji w itemsObservables.

Ostateczne zastosowanie dla jest zaznaczone ma na celu warunkowe ustawienie widoczności głównych obrazów.

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

Możemy to zrobić, dodając plik widoczny wiązanie do jest zaznaczone na div.item. Działa to poprzez bezpośrednie manipulowanie stylem elementu, więc każdy element, w którym jest zaznaczone ma wartość false, jego reguła wyświetlania CSS będzie ustawiona na Żaden, a wraz ze zmianą modelu widoku zmieni się także widoczność elementów.

Ponownie, jeśli przeglądamy w przeglądarce, rzeczy nie są takie, jakich oczekiwalibyśmy po galerii. Zwykle pierwszy obraz w zestawie byłby wybrany domyślnie, ale w obecnej chwili inicjalizujemy wszystkie elementy, aby mieć jest zaznaczone Ustawić fałszywe, więc żadne duże obrazy nie są widoczne, dopóki użytkownik go nie wybierze. Aby to obejść, ustawmy w metodzie init modelu głównego widoku jest zaznaczone na pierwszym elemencie do prawdziwe więc wyświetli się.

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

Oprócz tego przy użyciu wewnętrznych metod Knockout (takich jak Pchać, który jest raczej własnym językiem niż czystym JavaScriptem Pchać) na itemsObservables tablicę, możemy ją również nazwać za pomocą () a następnie uzyskaj dostęp do dowolnego z jego elementów, tak jak do zwykłej tablicy. Przypisujemy wartości do zwykłych obserwabli, wywołując je z wartością jako argumentem, czyli nową linią w w tym funkcja jest teraz ustawiona jest zaznaczone w pierwszej pozycji w obserwowalnej tablicy do prawdziwe.

Dopasowanie

Na razie mamy minimalną, ale funkcjonalną galerię zdjęć. Wyświetlany jest tylko jeden obraz z zestawu, a także miniatury, które użytkownik może kliknąć, aby wybrać, który ma być wyświetlany.

Zauważysz jednak, że przy głównych obrazach ustawionych na 800px szeroki, pasek miniatury przekracza tę szerokość - lub może nawet zawijać się, w zależności od rozmiaru przeglądarki. Byłoby lepiej, gdybyśmy mogli ograniczyć szerokość paska do rozmiaru obrazu i pozwolić mu przewijać w lewo lub w prawo, w zależności od tego, gdzie jest zaznaczenie. Oczywiście 800px to dowolna liczba dla tego demo. Może być dowolnego rozmiaru, a nawet reagować, ale radzenie sobie z tego typu sytuacjami jest miejscem, w którym Knockout naprawdę się sprawdza.

Aby dodać to zachowanie do interfejsu użytkownika, potrzebnych jest kilka nowych obserwacji, więc utworzymy zupełnie nowy model widoku, ScrollableArea, aby je przechowywać i śledzić - i zagnieżdżać to w naszym głównym modelu widoku, kiedy to definiujemy.

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

Jest tu jeszcze jedna nowa właściwość, o której warto wspomnieć, MeasureContent. Zobaczysz, że jest ustawiony na null i jest w zasadzie symbolem zastępczym funkcji, którą zdefiniujemy w naszym kodzie gotowym do dokumentu, dzięki czemu możemy skorzystać z niektórych funkcji jQuery bez wiązania go w naszym modelu widoku niezależnym od platformy. Wszystko inne związane z naszą rozszerzoną funkcjonalnością znajdzie się w ScrollableArea zobacz model.

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

Pierwszy fragment obserwabli śledzi stan interfejsu użytkownika. scrollThreshold to całkowita szerokość galerii obrazów. W praktyce tak będzie 800 ale to jest ogólny model widoku, więc zainicjujemy go 0; rzeczywisty rozmiar można przekazać podczas dokument gotowa funkcja. contentSize jest ponownie zainicjowany na 0, a będzie to miara całkowitej szerokości wszystkich elementów miniatur. Później porównamy te wartości, aby sprawdzić, czy obszar miniatur powinien się przewijać, czy nie.

Następne jest scrollValue, to jest zapis tego, gdzie powinna znajdować się „lewa” pozycja paska miniatury i znowu domyślnie 0. Wreszcie, scrollClickStep to ustawienie określające, o ile pasek miniatury powinien zostać przesunięty, gdy idziemy w lewo lub w prawo, a dla naszej wersji demonstracyjnej domyślnie jest to 400 (piksele).

Następnie przechodzimy do sprytnych rzeczy, w których siła Knockout staje się naprawdę widoczna. Jak dotąd mieliśmy do czynienia ko.observable i ko.observableArrayale istnieje trzeci typ obserwowalnych, ko.computed, który może obserwować dowolną liczbę innych obserwabli i zwróci obliczoną wartość na ich podstawie, gdy któraś z nich ulegnie zmianie. Mogą to być obliczenia tylko do odczytu lub dwukierunkowe funkcje odczytu / zapisu.

Zamiast tworzyć isScrollable prostą wartością, zamiast tego nazywamy ją funkcją, która w tym przypadku zwraca porównanie dwóch naszych poprzednich obserwabli, contentSize i scrollThreshold, aby sprawdzić, czy całkowita szerokość paska miniatur jest większa niż przestrzeń, w której mamy dostęp do jej wyświetlenia. W czasie inicjalizacji obie te wartości są 0, więc będzie fałszem - nie będzie przewijalny - ale gdy tylko zmierzymy DOM i umieścimy tam jakieś rzeczywiste wartości, zostanie on automatycznie przeliczony i wszystko w szablonie przypisanym do tego obliczonego obserwowalnego odpowie. Praktycznym sposobem jest rozszerzenie funkcji gotowości dokumentu, której już używamy do konfigurowania instancji modelu widoku głównego:

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

Teraz dodaliśmy zmienną do, który buforuje zapytanie DOM dla elementu zawierającego naszą listę pasków miniatur. Funkcja viewModel.measureContent (pamiętaj, że utworzyliśmy to jako funkcję zerową w Galeria zobacz model wcześniej) jest teraz definiowana jako po prostu zwracanie szerokości piksela pierwszego elementu listy w kontrolerze pomnożonej przez liczbę elementów, aby uzyskać całkowity rozmiar paska. Zakładanie, że wszystkie elementy mają tę samą szerokość, jest ryzykowne, ale w tej wersji demonstracyjnej wystarczy.

Ta funkcja służy do ustawiania wartości obserwowalnych przewijalny. scrollThreshold. Zauważ, że możemy ustawić wartości bezpośrednio na zagnieżdżonym poziomie modelu widoku, ponieważ wystąpienie ScrollableArea została zdefiniowana jako metoda publiczna, a jej obserwowalne są również publiczne. My też ustawiliśmy przewijalny. scrollThreshold do szerokości samego kontenera. Ważne jest, aby ustawić te wartości po zastosowaniu powiązań modelu widoku do modelu DOM, aby mieć pewność, że mierzymy w pełni wyrenderowany wynik, a nie puste szablony.

Zmiana wartości którejkolwiek z tych obserwabli powoduje isScrollable możliwe do ponownego obliczenia, a jeśli rozmiar zawartości jest teraz szerszy niż przestrzeń, którą mamy do dyspozycji, stanie się prawdą.

div> ul data-bind = "foreach: itemsObservables, style: {'width': scrollable.contentSize () + 'px'}"> ... / ul> button data-bind = "visible: scrollable.isScrollable, enable : scrollable.canScrollLeft, click: scrollable.scrollContent "data-direction =" left ">« / button> button data-bind = "visible: scrollable.isScrollable, enable: scrollable.canScrollRight, click: scrollable.scrollContent" data-direction = „w prawo”> »/ przycisk> / div>

Zrobić użytek z isScrollable w interfejsie użytkownika zmodyfikujemy również szablon paska miniatur. Zobaczysz, że jest plik styl wiążąc listę, aby ustawić jej szerokość na nasze poprzednie obliczenia; ma to na celu upewnienie się, że całość jest umieszczona w jednej linii, nawet jeśli plik pojemnik element będzie ograniczony do szerokości za pomocą przepełnienie: ukryte stosowany. Reszta szablonu elementu jest taka sama jak poprzednio, ale dodaliśmy też dwa przycisk elementy, z których oba mają rozszerzenie widoczny wiązanie do isScrollable. Prawdopodobnie możesz dowiedzieć się, jaki to ma wpływ; przyciski zostaną ustawione tak, aby wyświetlały się: none, dopóki isScrollable nie stanie się true, po czym pojawią się automatycznie.

Jest też plik włączyć wiązanie na tych guzikach. Nie będę zagłębiać się w szczegóły obliczonych obserwacji, które obliczają, czy są prawdziwe, czy fałszywe, ale zawierają logikę, która porównuje bieżącą pozycję przewijania z potencjalnymi wartościami maksymalnymi i minimalnymi i zapobiega przewijaniu przez użytkownika w lewo na lewym końcu paska miniatur i odwrotnie.

Wreszcie przyciski mają również Kliknij powiązanie z funkcją scrollContent, która dodaje lub odejmuje wartość kroku przewijania do bieżącej wartości przewijania w zależności od klikniętego kierunku. To ostatecznie ustawia inny obliczony obserwowalny na ScrollableArea zobacz model, obliczonaScrollValue.

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

Oto przykład dwukierunkowej, wyliczonej obserwowalnej, która zawiera funkcje zwrotne do odczytu i zapisu wartości. w czytać funkcja, na którą zareaguje na zmiany isScrollable, ale jeśli wywołasz go z wartością w argumencie, to pisać funkcja jest wyzwalana do ustawienia scrollValue, którego możemy użyć w styl oprawa na szablonie, aby ustawić pasek miniatury.

Podsumowując

Dość wiele koncepcji zostało szybko wprowadzonych w tym demo i byłoby ci wybaczone, gdyby niektóre z nich zrobiły więcej, aby zmylić niż oświetlić. Miejmy jednak nadzieję, że zauważyłeś pewne korzyści płynące z używania wzorca MVVM i chętnie poczytaj o nim dalej. Jak powiedzieliśmy na początku, dokumentacja i samouczki na stronie Knockout są fantastyczne i warte obejrzenia.

Jest też dużo więcej do załadowania, w tym niestandardowe powiązania, które można podłączyć bezpośrednio do metod efektów jQuery lub innych bibliotek. Więc zamiast prostego widoczny wiązanie możesz zdefiniować własne fadeVisible aby elementy pojawiały się i znikały z nieco większym stylem niż tylko pojawianie się, znikanie lub wyświetlanie.

Najważniejszą rzeczą do zapamiętania jest to, że we wszystkim, co opisano, chcieliśmy zachować czyste oddzielenie interfejsu użytkownika i logiki. Mogliśmy więc całkowicie zmienić widok, o ile wiązania zostały przeniesione, i wszystko nadal działałoby.

Istnieją oczywiście niezliczone, znacznie bogatsze w funkcje wtyczki galerii dla każdego środowiska JavaScript, o którym chciałbyś wspomnieć. Ale to tylko punkt wyjścia naszej galerii opartej na Knockout, a dla mnie zaletą robienia tego w ten sposób jest to, że otrzymujesz kompaktowy, ale rozszerzalny kontroler w postaci modelu widoku, który można zastosować do dowolnego interfejsu użytkownika bez martwienia się o to, jak ładnie będzie się bawić z istniejącą stroną.

To poprawiona, rozszerzona wersja artykułu opublikowanego po raz pierwszy na 12devsofxmas.co.uk

Odkryj 101 samouczków CSS i JavaScript, aby rozwinąć swoje umiejętności w Creative Bloq.

Artykuły Portalu.
Te trójwymiarowe portrety są niewiarygodnie realistyczne
Odkryć

Te trójwymiarowe portrety są niewiarygodnie realistyczne

Portrety 3D ą trudne do wykonania, ale ą zadziwiające, gdy ą wykonane prawidłowo. Zapoznanie ię z projektowaniem w 3D je t zczególnie trudne, gdy próbuje z naśladować obiekty ze świata rzecz...
Adobe Creative Cloud - Twoje za 38 GBP miesięcznie
Odkryć

Adobe Creative Cloud - Twoje za 38 GBP miesięcznie

Adobe ujawniło nam więcej zczegółów na temat wojej u ługi Creative Cloud - która ma zo tać uruchomiona w tym amym cza ie co C 6 je zcze w tym roku (daty je zcze do potwierdzenia). Adobe...
Jak malować odbicia w zbitym lustrze
Odkryć

Jak malować odbicia w zbitym lustrze

Podobnie jak w przypadku wielu ilu tracji przed tawiających rzeczywi te przedmioty codziennego użytku, trochę badań zaw ze pomaga. Oprócz przeprowadzenia wła nego ek perymentu polegającego na roz...