Konfigurowanie sprzętu i oprogramowania

Przykłady zastosowań na jednej stronie. Aplikacja jednostronicowa lub jednostronicowa aplikacja internetowa

Romana Lipskiego

Świat oprogramowania rozwija się obecnie z ogromną szybkością. Jeszcze kilka lat temu głównymi urządzeniami do tworzenia stron internetowych były komputery stacjonarne i laptopy. Dziś sytuacja wcale tak nie wygląda.

Uniwersalne aplikacje internetowe zastępują przestarzałe aplikacje desktopowe w wielu obszarach biznesu. Dlaczego? Ponieważ zachowują funkcjonalność na wszystkich urządzeniach, działają w chmurze i są ogólnie znacznie wygodniejsze w użyciu.

Niektórzy uważają, że aplikacje internetowe oparte na przeglądarce są stopniowo zastępowane przez aplikacje mobilne, które mają ogromną bazę klientów. Ale prawda jest taka, że ​​aplikacje internetowe żyją bardziej niż kiedykolwiek, a popyt na nie tylko rośnie.

Jeśli zastanawiasz się nad stworzeniem aplikacji internetowej dla swojej firmy, prawdopodobnie już wiesz, że istnieją dwa główne podejścia do rozwoju: możesz tworzyć zarówno aplikacje jednostronicowe (SPA), jak i aplikacje wielostronicowe (MPA).

Jak wszystko w naszym życiu, obie opcje projektowania mają swoje zalety i wady. Zanim zaczniesz wdrażać swoje pomysły, musisz podjąć kilka ważnych decyzji.

Aby zdecydować, który model aplikacji internetowej jest najlepszy dla Twojej firmy, zawsze skupiaj się na treściach, które Twoi klienci cenią najbardziej, ponieważ bez treści po prostu nie będziesz w stanie przyciągnąć klientów do korzystania z Twoich produktów internetowych.

Dlatego najważniejsze pytania na pierwszym etapie to, jaki rodzaj treści chcesz promować wśród docelowych odbiorców i co jest dla nich najważniejsze, aby z Tobą współpracować.

Jak wspomnieliśmy powyżej, zarówno SPA, jak i MPA mają swoje wady i zalety. Rozumiemy różnicę między tymi dwoma typami aplikacji i spróbujmy znaleźć odpowiednie rozwiązanie do tworzenia stron internetowych dla Twojej firmy.

W tym celu poprosimy dyrektora działu internetowego BLAKIT, Witalija Ozerskiego, o przedstawienie swoich eksperckich komentarzy na ten temat. Mamy nadzieję, że wspólnie ułatwimy Państwu ten wybór.

Aplikacje jednostronicowe

Aplikacje jednostronicowe działają w przeglądarce i nie wymagają ponownego ładowania stron ani ładowania dodatkowych stron podczas użytkowania. Z takich aplikacji codziennie korzystają miliony użytkowników, nawet tego nie zauważając. Najpopularniejsze przykłady: GitHub, Gmail, Google Maps, a nawet Facebook.

Witalij Ozerski: aplikacje jednostronicowe z reguły są maksymalnie interaktywne, do tego stopnia, że ​​użytkownik ma wrażenie, że pracuje z aplikacją desktopową: reakcja aplikacji na działania użytkownika jest w większości przypadków natychmiastowa. W ten sposób SPA wypadają korzystnie w porównaniu z witrynami wielostronicowymi, gdzie przy każdej akcji użytkownik musi czekać na załadowanie nowej strony.

Aplikacje jednostronicowe zostały zaprojektowane specjalnie w celu zapewnienia użytkownikom doskonałego UX, który przypomina „naturalne” środowisko przeglądarki, bez konieczności przeładowywania stron, a tym samym bez opóźnień w wykonywaniu działań.

Typowa aplikacja jednostronicowa wygląda jak strona internetowa, która ładuje i aktualizuje zawartość bez ponownego ładowania przy użyciu JavaScript. SPA żąda układu i treści strony, a następnie tworzy ostateczny widok strony bezpośrednio w przeglądarce. Efekt ten można osiągnąć dzięki zaawansowanym frameworkom JavaScript takim jak AngularJS, Ember.js, Meteor.js, Knockout.js.

W: Oprócz głównych popularnych frameworków programiści BLAKIT mogą także tworzyć aplikacje jednostronicowe przy użyciu ReactJS.

Główną zaletą React jest niski próg wejścia. React jest dość łatwy w użyciu; Prawie każdy programista znający HTML może tworzyć aplikacje React.

Kolejną zaletą jest możliwość pisania aplikacji na platformy webowe i mobilne przy wykorzystaniu jednego stosu technologicznego.

Korzystamy z React wraz z biblioteką Redux, co pozwala nam rozplanować odpowiednią architekturę i stworzyć złożone aplikacje internetowe, które są łatwe w skalowaniu.

Z punktu widzenia zwykłego użytkownika główną zaletą UX aplikacji typu single page jest to, że cała treść jest prezentowana w przystępny i funkcjonalny sposób, bez konieczności przeskakiwania ze strony na stronę.

Zalety aplikacji jednostronicowych:
  • SPA charakteryzują się doskonałą wydajnością, gdyż większość wykorzystywanych przez nie zasobów (HTML + CSS + Skrypty) ładuje się tylko raz podczas sesji korzystania z aplikacji. Po wykonaniu czynności na stronie zmieniają się jedynie dane.
  • Tworzenie aplikacji internetowych jest zazwyczaj szybsze i wydajniejsze. Nie ma potrzeby pisania osobnego kodu, aby wyrenderować stronę po stronie serwera. Dużo łatwiej jest także rozpocząć tworzenie takich aplikacji, ponieważ pisanie kodu można rozpocząć od pliku:://URI, bez konieczności korzystania z jakiegokolwiek serwera.
  • SPA są zoptymalizowane pod kątem debugowania Chrome, umożliwiając programistom śledzenie aktywności sieciowej oraz sprawdzanie elementów strony i powiązanych z nimi danych.
  • Jeśli posiadasz już SPA, będziesz mógł stworzyć aplikację mobilną z tym samym backendem.
  • SPA są bardziej wydajne w buforowaniu danych na nośnikach lokalnych. Aplikacja wysyła jedno żądanie, zbiera wszystkie niezbędne dane i od tego momentu może pracować nawet offline.
Wady aplikacji jednostronicowych:
  • Optymalizacja SEO dla aplikacji typu single page z oczywistych powodów nie jest zbyt łatwa. Treść aplikacji ładowana jest przy użyciu AJAX (Asynchronous JavaScript and XML), metody wymiany danych i aktualizacji aplikacji bez ponownego ładowania strony, natomiast optymalizacja SEO opiera się na trwałości treści na każdej pojedynczej stronie. Jednak wypromowanie Twojej strony w wyszukiwarkach nie jest niemożliwe. Wiele zmian w SEO można wprowadzić po stronie serwera, a firmy takie jak Google wciąż wymyślają nowe rozwiązania, aby ułatwić życie zarówno właścicielom spa, jak i ich użytkownikom.
  • Ładowanie zajmuje dość dużo czasu, ponieważ ciężkie frameworki po stronie klienta muszą najpierw zostać załadowane do przeglądarki.
  • SPA wymagają, aby JavaScript był aktywny w przeglądarkach użytkowników. Jeśli któryś z Twoich klientów ręcznie wyłączy JavaScript, nie będzie mógł w pełni korzystać z Twojej aplikacji. Nawet jeśli buforujesz i renderujesz swoje strony po stronie serwera (co jest teraz możliwe), nadal istnieje ryzyko, że nie dostarczysz wszystkich funkcji aplikacji jednostronicowej w prawidłowej formie użytkownikom nie korzystającym z JS.
  • W porównaniu do tradycyjnych aplikacji, SPA są nieco mniej bezpieczne. Dzięki skryptom krzyżowym (XSS) atakujący mogą wstrzyknąć dodatkowe skrypty po stronie klienta.
  • Niektóre wycieki pamięci JavaScript mogą powodować pogorszenie wydajności nawet w wydajnych systemach

Warto także wiedzieć, że wszystkie problemy związane z użytkowaniem aplikacji typu single page są stopniowo rozwiązywane, gdyż wiele firm, w tym korporacji technologicznych, zachęca do tej formy relacji z klientami w Internecie.

W: SPA są odpowiednie dla każdej firmy, która potrzebuje automatyzacji swoich procesów. Jednak w przypadku np. witryn korporacyjnych i katalogów internetowych lepiej jest korzystać z bardziej tradycyjnych witryn.

Aplikacje wielostronicowe

Aplikacje wielostronicowe działają, że tak powiem, w bardziej tradycyjny sposób. Każda istotna zmiana danych lub przesłanie informacji z powrotem na serwer powoduje wyświetlenie nowej strony w przeglądarce. Aplikacje wielostronicowe są oczywiście cięższe niż aplikacje jednostronicowe i zazwyczaj mają na celu wyświetlanie większej ilości treści.

Złożoność i koszt opracowania MPA są wyższe i wymagają również wielowarstwowego projektu interfejsu użytkownika. Na szczęście nie jest to już tak duży problem, ponieważ AJAX pozwala na aktualizację tylko niektórych części aplikacji, zamiast przesyłać masę danych pomiędzy serwerami i przeglądarkami.

Zalety aplikacji wielostronicowych:
  • Jest to najbardziej odpowiednia opcja dla użytkowników, którzy chcą bardziej przejrzystego wizualnie interfejsu i znanej nawigacji po aplikacji. MPA są zwykle tworzone z wielopoziomowymi menu i innymi narzędziami nawigacyjnymi.
  • Znacząco uproszczone SEO. Możesz zoptymalizować każdą stronę aplikacji pod kątem potrzebnych słów kluczowych.
Wady aplikacji wielostronicowych:
  • Rozwój frontendu i backendu w tym przypadku są bardzo ściśle ze sobą powiązane.
  • Rozwój MPA jest dość złożony, ponieważ wymaga użycia frameworków zarówno po stronie klienta, jak i serwera. Odpowiednio czas i koszty rozwoju nie są dla wielu firm tak przyjemne.
SPA czy MPA?

Zanim podejmiesz decyzję o stworzeniu aplikacji internetowej, musisz najpierw mieć na uwadze cel jej powstania. Jeśli w biznesie masz do czynienia z dużą liczbą różnych towarów i usług, wielostronicowy serwis internetowy będzie dla Ciebie optymalnym rozwiązaniem.

Jeśli szukasz maksymalnej funkcjonalności w skondensowanej przestrzeni internetowej, jednostronicowa aplikacja internetowa jest właściwym wyborem. A jeśli funkcjonalność SPA odpowiada Twoim potrzebom, ale nie możesz sobie wyobrazić, jak zmieścić całą treść na jednej stronie, warto rozważyć witrynę hybrydową.

Nie wspominaliśmy jeszcze o tej formie tworzenia stron internetowych w artykule. Aplikacja hybrydowa ma na celu wykorzystanie tego, co najlepsze z obu światów, jednocześnie minimalizując wady.

Technicznie rzecz biorąc, aplikacja hybrydowa to nadal SPA, ale wykorzystuje kotwice adresów URL jako strony syntetyczne, poprawiając w ten sposób natywną nawigację i funkcjonalność ustawień przeglądarki.

Daj nam znać, jeśli chcesz dowiedzieć się więcej o aplikacjach hybrydowych, napiszemy o nich osobny artykuł.

Obecnie uważa się, że w najbliższej przyszłości prawie wszystkie firmy przejdą na model aplikacji jednostronicowy lub hybrydowy, ponieważ taka architektura ma więcej zalet zarówno dla programistów, jak i użytkowników.

Z naszych danych wynika, że ​​wiele rodzajów przedsiębiorstw już w swojej strategii promocji w Internecie przechodzi na ten model. Jednak niektórych typów projektów po prostu nie da się wdrożyć jako SPA: po prostu zawierają za dużo treści. Dlatego przynajmniej w najbliższej przyszłości model MPA nadal ma swoje miejsce.

W: Całkowicie zgadzam się ze stwierdzeniem o rosnącej popularności aplikacji jednostronicowych. W dzisiejszych czasach aplikacje SPA cieszą się dużym zainteresowaniem, gdyż firmy stopniowo przenoszą swoje oprogramowanie z aplikacji desktopowych do aplikacji dostępnych z dowolnej przeglądarki, a nie tylko na komputerze PC z systemem Windows.

Aplikacje internetowe w chmurze zyskują na popularności. Wiele firm IT dostrzega ten trend i coraz więcej oprogramowania powstaje w oparciu o zdalny dostęp. Istnieje wiele podobnych programów komputerowych, które oferują wersję online za niewielką miesięczną opłatą.

Zapewniają większą elastyczność i mobilność. Przykładowo, dane do chmurowych systemów CRM czy ERP możesz łatwo wprowadzić za pomocą telefonu komórkowego i może to nastąpić w dogodnym dla Ciebie miejscu. Jak widać z wykresu Statisty, rynek rozwiązań chmurowych rośnie i do 2026 roku ma osiągnąć prawie 522 miliardy dolarów.

Aby zapewnić stabilne działanie skomplikowanych aplikacji internetowych, wskazane jest stosowanie technologii, które zapewnią najlepszą wydajność i szybkość. Istnieją dwa sposoby tworzenia aplikacji internetowych: aplikacje jednostronicowe (SPA) i aplikacje wielostronicowe (MPA). Przyjrzyjmy się różnicy między nimi i jakie zalety ma każdy typ aplikacji internetowej.

Single Page Applications pozwalają symulować pracę aplikacji desktopowych. Architektura została zaprojektowana w taki sposób, że po przejściu na nową stronę aktualizowana jest tylko część treści. Dzięki temu nie ma potrzeby ponownego pobierania tych samych elementów. Jest to bardzo wygodne dla programistów i użytkowników. Do tworzenia SPA wykorzystuje się jeden z najpopularniejszych języków programowania – JavaScript. Za pomocą biblioteki jQuery można utworzyć małą aplikację internetową.

Warto jednak od razu zaznaczyć, że jQuery bardzo słabo nadaje się do tworzenia dużych projektów. Nasza firma Merehead zaleca stosowanie bardziej wydajnych technologii do rozwoju SPA. React.js, Angular.js, Vue.js i inne frameworki/biblioteki doskonale nadają się do tych celów. Ich architektura pozwala na tworzenie elastycznych aplikacji internetowych. Co więcej, w oparciu o frameworki można budować aplikacje mobilne z możliwością wielokrotnego użycia. Takie możliwości dają Rreact Native i Ionic. Główne zalety aplikacji jednostronicowej:

  • Wysoka prędkość. Ponieważ SPA nie aktualizuje całej strony, a tylko niezbędną część, znacznie przyspiesza to pracę.
  • Wysoka prędkość rozwoju. Gotowe biblioteki i frameworki zapewniają potężne narzędzia do tworzenia aplikacji internetowych. Programiści back-end i front-end mogą pracować nad projektem równolegle. Dzięki wyraźnemu oddzieleniu nie będą sobie wzajemnie przeszkadzać.
  • Aplikacje mobilne. SPA ułatwia tworzenie aplikacji mobilnej w oparciu o gotowy kod.
  • Mimo wszystkich swoich zalet, aplikacja jednostronicowa ma pewne wady, które utrudniają wzrost popularności:

  • Słaba optymalizacja SEO. SPA działa na javascript i ładuje informacje na żądanie klienta. Wyszukiwarkom trudno jest naśladować takie zachowanie. Dlatego większość stron po prostu nie jest możliwa do przeszukania przez boty wyszukiwania.
  • Nieaktywny JavaScript. Niektórzy użytkownicy wyłączają JavaScript w swoich przeglądarkach i bez tego Twoja aplikacja nie będzie działać.
  • Niski poziom bezpieczeństwa.
  • JavaScript ma niski poziom bezpieczeństwa, ale jeśli korzystasz z nowoczesnych frameworków, mogą one zapewnić bezpieczeństwo Twojej aplikacji internetowej. Warto jednak zaznaczyć, że korzystanie z jQuery może znacząco obniżyć bezpieczeństwo Twojego projektu.

    Jednostronicowe aplikacje internetowe doskonale nadają się do tworzenia dynamicznych platform z niewielką ilością danych. Dodatkowo, jeśli w przyszłości będziesz musiał zbudować aplikację mobilną, SPA będzie idealne jako baza. Główną wadą powstrzymującą szybki wzrost popularności SPA jest słaba optymalizacja SEO. Projekty, w których SEO jest najwyższym priorytetem, powinny korzystać z MPA.

    Aplikacja wielostronicowa (MPA)

    Aplikacje wielostronicowe mają bardziej klasyczną architekturę. Każda strona wysyła żądanie do serwera i całkowicie aktualizuje wszystkie dane. Nawet jeśli te dane są niewielkie. W związku z tym wydajność jest marnowana na wyświetlanie tych samych elementów. W związku z tym wpływa to na szybkość i wydajność. Wielu programistów używa JavaScript/jQuery w celu zwiększenia szybkości i zmniejszenia obciążenia. Dobrym przykładem jest aktualizacja produktów bez przeładowywania strony przy korzystaniu z filtrów w sklepie internetowym. Jest to o wiele wygodniejsze i co najważniejsze szybsze. Główne zalety aplikacji wielostronicowej (MPA):

  • Łatwa optymalizacja SEO. Architektura MPA sprawia, że ​​optymalizacja każdej strony pod kątem wyszukiwarek jest dość łatwa.
  • Łatwy rozwój. Zazwyczaj tworzenie aplikacji wielostronicowej wymaga mniejszego stosu technologii.
  • Wiele rozwiązań.
  • Korzystając z MPA, możesz znaleźć odpowiednie rozwiązanie pudełkowe. Na przykład użyj Magento, OpenCart do opracowania aplikacji internetowej e-commerce lub Dolphin, Elgg do rozwoju sieci społecznościowych. Wady MPA:

  • Tworzenie aplikacji mobilnych potrwa znacznie dłużej. W większości przypadków będziesz musiał napisać backend od zera.
  • Trudno jest oddzielić front-end od back-endu. Z reguły bardzo ściśle ze sobą współdziałają. Praca programistów front-end i back-end staje się coraz bardziej skomplikowana.
  • Główną zaletą MPA jest dobra optymalizacja SEO i ogromna ilość pakietowanych rozwiązań.

    Termin „aplikacja jednostronicowa” (lub SPA) jest powszechnie używany do opisu aplikacji stworzonych dla Internetu. Aplikacje te są dostępne za pośrednictwem przeglądarki internetowej, podobnie jak inne witryny internetowe, ale oferują bardziej dynamiczne wrażenia, przypominające natywne aplikacje mobilne i stacjonarne.

    Najbardziej zauważalną różnicą pomiędzy zwykłą witryną a SPA jest zmniejszenie liczby aktualizacji strony. Spa w większym stopniu wykorzystuje technologię AJAX — sposób komunikowania się z serwerami zaplecza bez całkowitego odświeżania strony — w celu ładowania danych do naszej aplikacji. W rezultacie proces renderowania (budowania) stron odbywa się przede wszystkim po stronie klienta przy użyciu JavaScript.

    SPA, aplikacja jednostronicowa

    Choć budowanie aplikacji SPA jest modne i uważane za nowoczesną praktykę deweloperską, warto zdawać sobie sprawę z jej wad, do których zaliczają się:

    • Przeglądarka wykonuje większość zadań, co oznacza, że ​​wydajność może stanowić problem – szczególnie na mniej wydajnych urządzeniach mobilnych.
    • Trudność optymalizacji wyszukiwarek (SEO), trudność w prezentowaniu treści wyszukiwarkom i serwisom społecznościowym, które udostępniają podgląd linków.
    Łagodzenie wad dzięki renderowaniu po stronie serwera

    Większość współczesnych frameworków JavaScript pracuje nad obsługą renderowania serwera SPA, tj. użytkownik otrzyma całkowicie zapełnioną stronę przy pierwszym załadowaniu SPA, zamiast na przykład widzieć wskaźnik ładowania.

    Renderowanie po stronie serwera może odciążyć niektóre prace związane z blogiem, które przeglądarki muszą wykonywać podczas renderowania stron, a także może pomóc w rozwiązywaniu problemów związanych z SEO i dostępnością treści.

    Popularne frameworki i biblioteki JavaScript do tworzenia SPA

    Im więcej interaktywności dzieje się po stronie klienta, tym więcej kodu JavaScript potrzeba, aby te interaktywne elementy działały dobrze. Im więcej kodu jest napisane, tym ważniejsze jest posiadanie czystej i dobrze zaprojektowanej bazy kodu. I to jest właśnie problem, który rozwiązują frameworki JavaScript, każdy z własnym podejściem.

    Istnieje wiele frameworków JavaScript typu open source, które pomagają tworzyć aplikacje SPA, takie jak.

    Produkty i technologie:

    Aplikacje jednostronicowe (SPA), ASP.NET Web API, Knockout.js, Ember.js, AJAX i HTML5

    W artykule omówiono:

    • Utwórz warstwę usług i klienta WWW AJAX dla przykładowej aplikacji;
    • wzorce MVC i MVVM;
    • powiązanie danych;
    • utworzenie klienta WWW przy użyciu Knockout.js;
    • utworzenie klienta WWW przy użyciu Ember.js.

    Aplikacje jednostronicowe (SPA) to aplikacje internetowe, które ładują pojedynczą stronę HTML i dynamicznie ją aktualizują po interakcji użytkownika.

    SPA używają AJAX i HTML5 do tworzenia elastycznych i responsywnych aplikacji internetowych bez ciągłego przeładowywania stron. Oznacza to jednak, że większość pracy spada po stronie klienta, czyli nad kodem JavaScript. Dla tradycyjnego programisty ASP.NET może to być trudne do osiągnięcia. Na szczęście istnieje wiele frameworków JavaScript typu open source, które ułatwiają tworzenie SPA.

    W tym artykule przeprowadzę Cię krok po kroku przez proces tworzenia prostej aplikacji SPA. Po drodze poznasz kilka podstawowych koncepcji tworzenia SPA, w tym wzorce Model-View-Controller (MVC) i Model-View-ViewModel (MVVM), powiązanie danych i routing.

    O przykładowej aplikacji

    Stworzyłem przykładową aplikację do działania na prostej bazie filmów (Rysunek 1). W lewej kolumnie strony wyświetlana jest lista gatunków. Wybranie gatunku powoduje wyświetlenie listy powiązanych filmów. Przycisk Edytuj obok wpisu umożliwia zmianę tego wpisu. Po edycji możesz kliknąć przycisk Zapisz, aby wysłać aktualizację na serwer lub przycisk Anuluj, aby odrzucić zmiany.

    Ryż. 1. Aplikacja SPA dla bazy filmów

    Stworzyłem dwie wersje tej aplikacji: jedną wykorzystującą bibliotekę Knockout.js i drugą korzystającą z biblioteki Ember.js. Obie biblioteki opierają się na różnych podejściach, dlatego porównanie ich będzie dość pouczające. W obu przypadkach aplikacja kliencka nie wymagała więcej niż 150 linii kodu JavaScript. Po stronie serwera wykorzystałem interfejs API sieci Web ASP.NET do obsługi klienta w formacie JSON. Kod źródłowy obu wersji można znaleźć na stronie github.com/MikeWasson/MoviesSPA.

    (Uwaga: Aplikację stworzyłem przy użyciu wersji RC programu Visual Studio 2013. Niektóre rzeczy mogły ulec zmianie w wersji RTM, ale nie powinny mieć wpływu na kod.)

    Recenzja

    W tradycyjnej aplikacji internetowej przy każdym wywołaniu serwera renderowana jest nowa strona HTML. Spowoduje to odświeżenie strony w przeglądarce. Jeśli kiedykolwiek pisałeś formularze internetowe lub aplikację w języku PHP, ten cykl życia strony powinien być Ci znany.

    W SPA po załadowaniu pierwszej strony cała interakcja z serwerem odbywa się poprzez wywołania AJAX. Te wywołania AJAX zwracają dane (nie znaczniki) - zwykle w formacie JSON. Aplikacja wykorzystuje dane JSON do dynamicznej aktualizacji strony bez jej ponownego ładowania. Ryż. Rysunek 2 ilustruje różnicę między tymi dwoma podejściami.


    Ryż. 2. Porównanie tradycyjnego cyklu życia strony z cyklem życia w SPA

    Jedna z zalet SPA jest oczywista: aplikacje są bardziej elastyczne i adaptacyjne, wolne od postrzępionego efektu przeładowywania strony i ponownego jej renderowania. Kolejna korzyść może być mniej oczywista i dotyczy sposobu projektowania architektury aplikacji internetowej. Wysyłanie danych aplikacji w formacie JSON zapewnia oddzielenie części prezentacyjnej (znaczniki HTML) od logiki aplikacji (żądania AJAX i odpowiedzi JSON).

    Podział ten upraszcza projektowanie i rozwój każdego poziomu. W dobrze zaprojektowanej aplikacji SPA możesz zmienić znaczniki HTML bez dotykania kodu implementującego logikę aplikacji (przynajmniej idealnie). Zobaczysz to w praktyce, kiedy omówimy wiązanie danych.

    W czystym SPA cała interakcja z interfejsem użytkownika odbywa się po stronie klienta za pośrednictwem JavaScript i CSS. Po początkowym załadowaniu strony serwer działa wyłącznie jako warstwa usług. Klient musi tylko wiedzieć, jakie żądania HTTP powinien wysłać. Nie ma dla niego znaczenia, w jaki sposób serwer realizuje swoją część.

    Dzięki tej architekturze klient i usługa są niezależne. Możesz całkowicie zastąpić backend obsługujący usługę i dopóki nie zmienisz interfejsu API, nie uszkodzisz w żaden sposób klienta. Jest też odwrotnie: możesz wymienić całą aplikację kliencką bez zmiany warstwy usług. Można na przykład napisać natywnego klienta mobilnego korzystającego z tej usługi.

    Tworzenie projektu w Visual Studio

    Program Visual Studio 2013 ma jeden typ projektu aplikacji sieci Web ASP.NET. Kreator tego projektu umożliwia wybranie komponentów ASP.NET, które zostaną uwzględnione w projekcie. Zacząłem od pustego szablonu, a następnie dodałem do projektu interfejs API sieci Web ASP.NET, zaznaczając pole wyboru Interfejs API sieci Web w obszarze Dodaj foldery i podstawowe odniesienia dla, jak pokazano na rysunku 1. 3.


    Ryż. 3. Utwórz nowy projekt ASP.NET w Visual Studio 2013

    Nowy projekt zawiera wszystkie biblioteki potrzebne do Web API, a także trochę kodu konfiguracyjnego Web API. Nie wprowadziłem żadnych zależności do formularzy internetowych ani ASP.NET MVC.

    Zwróć uwagę na rys. 3, że Visual Studio 2013 zawiera szablon aplikacji jednostronicowej. Ten szablon instaluje szkieletową aplikację SPA opartą na Knockout.js. Obsługuje logowanie przy użyciu bazy danych członkostwa grupy lub przy użyciu zewnętrznego dostawcy uwierzytelniania. Nie użyłem tego wzorca w mojej aplikacji, ponieważ chciałem pokazać prostszy przykład od zera. Szablon SPA jest doskonałym zasobem, szczególnie jeśli chcesz dodać uwierzytelnianie do swojej aplikacji.

    Tworzenie warstwy usług

    Do stworzenia prostego interfejsu API REST dla aplikacji użyłem ASP.NET Web API. Nie będę się tutaj wdawał w szczegóły Web API - szczegóły można przeczytać pod linkiem asp.net/web-api.

    Najpierw utworzyłem klasę Movie, która reprezentuje film. Ta klasa robi dwie rzeczy:

    • informuje Entity Framework (EF), jak tworzyć tabele bazy danych do przechowywania informacji o filmie;
    • informuje interfejs API sieci Web, jak sformatować ładunek JSON.

    Nie musisz używać tego samego modelu do obu celów. Na przykład możesz chcieć, aby schemat bazy danych różnił się od ładunku JSON. W tej aplikacji stawiam na prostotę:

  • przestrzeń nazw MoviesSPA.Models
  • Film klasy publicznej
  • publiczny identyfikator int (get; set;)
  • publiczny ciąg Tytuł ( get; set; )
  • public int Rok ( get; set; )
  • public string Gatunek ( get; set; )
  • ciąg publiczny Ocena ( get; set; )
  • Następnie wykorzystałem technologię rusztowania programu Visual Studio do utworzenia kontrolera interfejsu API sieci Web, który wykorzystuje EF jako warstwę danych. Aby zastosować tę technologię, kliknij prawym przyciskiem myszy folder Kontrolery w Eksploratorze rozwiązań i wybierz opcję Dodaj/nowy element szkieletowy. W kreatorze dodawania szkieletu określ kontroler Web API 2 z akcjami, używając Entity Framework, jak pokazano na rysunku. 4.


    Ryż. 4. Dodanie kontrolera Web API

    Na ryc. Rysunek 5 przedstawia kreatora dodawania kontrolera. Nazwałem kontroler MoviesController. Nazwa ma znaczenie, ponieważ identyfikatory URI interfejsów API REST są oparte na nazwie kontrolera. Zaznaczyłem także pole wyboru Użyj akcji kontrolera asynchronicznego, aby skorzystać z nowej funkcjonalności asynchronicznej w EF 6. Wybrałem klasę Film jako model i określiłem Nowy kontekst danych, aby utworzyć nowy kontekst danych EF.


    Ryż. 5. Kreator dodawania kontrolera

    Kreator dodaje dwa pliki:

    • MoviesController.cs – definiuje kontroler Web API, który implementuje REST API dla aplikacji;
    • MovieSPAContext.cs to w zasadzie warstwa kleju EF, która udostępnia metody wykonywania zapytań do podstawowej bazy danych.

    W tabeli Rysunek 1 przedstawia domyślny interfejs API REST wygenerowany przez technologię rusztowania.

    Tabela 1. Domyślny interfejs API REST utworzony poprzez szkielet z interfejsu Web API

    Wartości w nawiasach klamrowych są symbolami zastępczymi symboli wieloznacznych. Na przykład, aby uzyskać film o identyfikatorze 5, identyfikator URI będzie wyglądał następująco: /api/movies/5.

    Rozszerzyłem to API, dodając metodę, która wyszukuje wszystkie filmy określonego gatunku:

    Klient określa gatunek w ciągu zapytania URI. Na przykład, aby pobrać wszystkie filmy z gatunku Dramat, klient wysyła żądanie GET do /api/movies?genre=drama. Interfejs API sieci Web automatycznie kojarzy parametr żądania z parametrem gatunku w metodzie GetMoviesByGenre.

    Tworzenie klienta internetowego

    Do tej pory tworzyłem API REST. Jeśli wyślesz żądanie GET do /api/movies?genre=drama, początkowa odpowiedź HTTP będzie wyglądać następująco:

    HTTP/1.1 200 OK Kontrola pamięci podręcznej: brak pamięci podręcznej Pragma: brak pamięci podręcznej Typ zawartości: aplikacja/json; charset=utf-8 Data: wtorek, 10 września 2013 15:20:59 GMT Długość treści: 240 [("ID":5",Title":"Forgotten Doors","Year":2009,"Gatunek": „Dramat”, „Rating”: „R”), („ID”: 6, „Tytuł”: „Blue Moon June”, „Rok”: 1998, „Gatunek”: „Dramat”, „Rating”: „PG” -13"),("ID":7,"Tytuł":"Na krawędzi słońca","Rok":1977,"Gatunek":"Dramat","Ocena":"PG-13")]

    Teraz muszę napisać aplikację kliencką, która zrobi z tym coś znaczącego. Podstawowy przebieg pracy to:

    • Interfejs użytkownika inicjuje żądanie AJAX;
    • zaktualizuj kod HTML, aby wyświetlić ładunek odpowiedzi;
    • Obsługujemy błędy AJAX.

    Można by to wszystko zakodować ręcznie. Na przykład oto kod jQuery, który tworzy listę tytułów filmów:

  • $.getJSON(adres URL)
  • .done(funkcja (dane) (
  • // Jeśli się powiedzie, dane zawierają listę filmów
  • var ul = $("")
  • $.each(dane, funkcja (klucz, pozycja) (
  • // Dodaj element do listy
  • $("
  • ", (tekst: poz.Tytuł )).appendTo(ul);
  • $("#filmy").html(ul);
  • Występują pewne problemy z tym kodem. Łączy logikę aplikacji z logiką prezentacji i jest ściśle powiązany z kodem HTML. Poza tym pisanie tego jest dość nudne. Zamiast skupiać się na aplikacji, spędzasz czas na pisaniu procedur obsługi zdarzeń i kodu manipulującego DOM.

    Rozwiązaniem jest użycie frameworka JavaScript. Na szczęście jest ich sporo do wyboru, a te frameworki są open source. Niektóre z bardziej popularnych frameworków to Backbone, Angular, Ember, Knockout, Dojo i JavaScriptMVC. Większość ludzi używa odmian wzorców MVC lub MVVM, warto więc szybko przyjrzeć się tym wzorcom.

    Wzorce MVC i MVVM

    Korzenie wzorca MVC sięgają lat 80. XX wieku i są kojarzone z wczesnymi graficznymi interfejsami użytkownika. Celem MVC jest podzielenie kodu na trzy poziomy z własnymi obowiązkami (rys. 6). Oto, co robią:

    • model reprezentuje dane i logikę biznesową domeny;
    • widok wyświetla model;
    • kontroler akceptuje dane wejściowe użytkownika i aktualizuje model.

    Ryż. 6. Wzorzec MVC

    Bardziej nowoczesną odmianą MVC jest wzorzec MVVM (ryc. 7). W szablonie MVVM:

    • model nadal reprezentuje dane domeny;
    • model widoku jest abstrakcyjnym odzwierciedleniem widoku;
    • widok renderuje model widoku i wysyła dane wejściowe użytkownika do modelu widoku.

    Ryż. 7. Wzór MVVM

    Zobacz model Zobacz model

    W frameworku JavaScript MVVM widok to znacznik, a model prezentacji to kod.

    MVC ma wiele odmian, a literatura na temat MVC jest często sprzeczna i zagmatwana. Być może nie jest to zaskakujące w przypadku wzorca projektowego, który rozpoczął życie w Smalltalk-76 i nadal jest używany w nowoczesnych aplikacjach internetowych. Tak więc, chociaż dobrze jest znać teorię, kluczem jest zrozumienie konkretnego frameworka MVC, którego używasz.

    Tworzenie klienta sieciowego przy użyciu Knockout.js

    W pierwszej wersji mojej aplikacji wykorzystałem bibliotekę Knockout.js. Knockout podąża za wzorcem MVVM, łącząc widok i model widoku poprzez powiązanie danych.

    Aby utworzyć powiązania danych, do elementów HTML dodajesz specjalny atrybut powiązania danych. Na przykład następujący znacznik kojarzy element span z właściwością gatunku w modelu widoku. Za każdym razem, gdy zmienia się wartość gatunku, Knockout automatycznie aktualizuje kod HTML:

  • Powiązania mogą również działać w drugą stronę, np. jeśli użytkownik wprowadzi tekst w polu, Knockout aktualizuje odpowiednią właściwość w modelu widoku.

    Wygodne jest, aby wiązanie danych odbywało się deklaratywnie. Nie musisz łączyć modelu widoku z elementami strony HTML. Po prostu dodaj atrybut wiązania danych, a Knockout zajmie się resztą.

    Zacząłem od utworzenia strony HTML z podstawowymi znacznikami bez wiązania danych, jak pokazano na rysunku. 8.

    Ryż. 8. Początkowe znaczniki HTML

  • Filmy SPA
  • TytułRokOcena
  • Nic nie znaleziono.

  • (Uwaga: do stylizacji wyglądu aplikacji użyłem Bootstrapa, więc sama aplikacja zawiera mnóstwo dodatkowych elementów i klas CSS kontrolujących formatowanie. Dla przejrzystości usunąłem to wszystko z kodu).

    Tworzenie modelu widoku

    Obserwowalne elementy mają kluczowe znaczenie dla systemu wiązania danych w Knockout. Obserwowalny to obiekt przechowujący wartość i mogący powiadamiać subskrybentów o zmianie tej wartości. Poniższy kod konwertuje reprezentację filmu w formacie JSON na równoważny obiekt z obserwowalnymi polami:

  • funkcja film(dane) (
  • var self = to;
  • dane = dane // ();
  • // Dane z modelu
  • self.ID = data.ID;
  • self.Title = ko.observable(data.Title);
  • self.Year = ko.observable(data.Year);
  • self.Rating = ko.observable(data.Rating);
  • self.Genre = ko.observable(data.Genre);
  • Na ryc. Rysunek 9 przedstawia początkową implementację modelu widoku. Ta wersja obsługuje tylko pobieranie listy filmów. Później dodam narzędzia do edycji. Model widoku zawiera obserwowalne właściwości listy filmów, ciąg błędów i bieżący gatunek.

    Ryż. 9. Model prezentacji

  • var ViewModel = funkcja() (
  • var self = to;
  • // Obserwowalne właściwości modelu widoku
  • self.movies = ko.observableArray();
  • self.error = ko.observable();
  • // Gatunek aktualnie oglądany przez użytkownika
  • self.gatunek = ko.observable();
  • // Dostępne gatunki
  • self.genres = ["Akcja", "Dramat", "Fantasy", "Horror", "Komedia romantyczna"];
  • // Dodaj tablicę JSON obiektów filmowych
  • // do modelu widoku
  • funkcja dodajMovies(dane) (
  • var mapped = ko.utils.arrayMap(dane, funkcja (element) (
  • zwróć nowy film (przedmiot);
  • self.movies(mapowane);
  • // Wywołanie zwrotne w celu odebrania błędów z serwera
  • funkcja onError(błąd) (
  • self.error("Błąd: " + error.status + " " + error.statusText);
  • // Uzyskaj listę filmów według gatunku
  • // i zaktualizuj model widoku
  • self.getByGenre = funkcja (gatunek) (
  • self.error(""); // usuń błąd
  • self.gatunek(gatunek);
  • // Zainicjuj aplikację, otrzymując pierwszy gatunek
  • self.getByGenre(self.gatunki);
  • // Utwórz instancję modelu widoku i przekaż ją do Knockout
  • ko.applyBindings(nowy ViewModel());
  • Należy pamiętać, że filmy znajdują się w tablicy obserwowalnej. Jak sama nazwa wskazuje, observableArray działa jak tablica powiadamiająca subskrybentów o zmianie jej zawartości.

    Funkcja getByGenre wysyła do serwera żądanie AJAX w celu uzyskania listy filmów, a następnie wypełnia tablicę self.movies wynikami.

    Podczas korzystania z interfejsu API REST jedną z najtrudniejszych części jest obsługa asynchronicznego charakteru protokołu HTTP. Funkcja ajax jQuery zwraca obiekt, który implementuje API Promises. Możesz użyć metody then obiektu Promise, aby skonfigurować wywołanie zwrotne uruchamiane w przypadku powodzenia wywołania AJAX i uruchamiające kolejne wywołanie zwrotne w przypadku niepowodzenia wywołania AJAX:

  • app.service.byGenre(gatunek).then(addMovies, onError);
  • Powiązania danych

    Teraz, gdy mam model widoku, mogę powiązać go z HTML za pomocą powiązań danych. Aby uzyskać pełną listę gatunków, która pojawia się po lewej stronie ekranu, używam następujących powiązań danych:

  • Atrybut data-bind zawiera jedną lub więcej deklaracji powiązania, przy czym każde powiązanie ma postać „powiązanie: wyrażenie”. W tym przykładzie powiązanie foreach nakazuje Knockoutowi przeglądanie zawartości tablicygatunki w modelu widoku. Dla każdego elementu tablicy Knockout tworzy nowy element

  • . Tekst w powiązaniu przypisuje tekstowi w rozpiętości wartość elementu tablicy, która w tym przypadku jest nazwą gatunku.

    W tej chwili kliknięcie nazwy gatunku nic nie daje, więc dodaję powiązanie kliknięcia do obsługi zdarzeń kliknięcia:

  • Spowoduje to powiązanie zdarzenia kliknięcia z funkcją getByGenre w modelu widoku. Tutaj konieczne było użycie $parent, ponieważ to wiązanie jest wykonywane w kontekście foreach. Domyślnie powiązania w foreach odnoszą się do bieżącego elementu w pętli.

    Ryż. 10. Dodanie kotwic do tabeli w celu wyświetlenia listy filmów

    Na ryc. 10 wiązanie foreach przechodzi przez tablicę obiektów filmowych. Wewnątrz foreach powiązania tekstu odnoszą się do właściwości bieżącego obiektu.

    Widoczne wiązanie na elemencie

    kontroluje, czy tabela jest renderowana. Tabela zostanie ukryta, jeśli tablica filmów będzie pusta.

    Na koniec, oto powiązania dla komunikatu o błędzie i komunikatu „Nie znaleziono rekordów” (pamiętaj, że w powiązaniu możesz umieścić złożone wyrażenia):

    Nic nie znaleziono.

    Edycja wpisów

    Ostatnia część aplikacji umożliwia edycję wpisów w tabeli. Wymaga to następującej funkcjonalności:

    • przełączać pomiędzy trybem przeglądania (tylko tekst) i edycji (kontrola wprowadzania);
    • przesyłanie aktualizacji na serwer;
    • obsługa cofania zmian i przywracania oryginalnych danych.

    Aby śledzić tryb przeglądania/edycji, dodałem flagę boolowską do obiektu filmu jako obserwowalną właściwość:

  • funkcja film(dane) (
  • // Inne właściwości pominięte
  • self.editing = ko.observable(false);
  • Potrzebowałem tabeli filmów, aby wyświetlać tekst, gdy właściwość edycji ma wartość false, ale przełączać się na kontrolki wejściowe, gdy jest to prawda. Aby to zrobić, użyłem wiązań typu knockout if i ifnot, jak pokazano na ryc. jedenaście. Składnia „” umożliwia dołączenie powiązań if i ifnot bez umieszczania ich w elemencie kontenera HTML.

    Ryż. 11. Wsparcie edycji wpisów filmowych

  • Powiązanie wartości określa wartość kontrolki wejściowej. Jest to powiązanie dwukierunkowe, więc gdy użytkownik wpisze coś w polu tekstowym lub zmieni wybór na liście rozwijanej, zmiana zostanie automatycznie przeniesiona do modelu widoku.

    Powiązałem moduły obsługi kliknięć przycisków z funkcjami zapisywania, anulowania i edycji w modelu widoku.

    Funkcja edycji jest prosta. Wystarczy ustawić flagę edycji na true:

  • self.edit = funkcja (element) (
  • pozycja.edycja(true);
  • Funkcje zapisywania i anulowania są nieco bardziej skomplikowane. Aby móc cofać, potrzebowałem sposobu na buforowanie oryginalnej wartości podczas edycji. Na szczęście Knockout ułatwia rozszerzenie zachowania obserwowalnych. W kodzie na rys. 12 dodaje funkcję store do klasy obserwowalnej. Wywołanie funkcji store z obserwowalnego daje tej klasie dwie nowe funkcje: przywracanie i zatwierdzanie.

    Ryż. 12. Rozszerzanie ko.observable o funkcje revert i commit

  • var self = to;
  • var staraWartość = self();
  • czytaj: funkcja() (
  • zwróć siebie();
  • napisz: funkcja (wartość) (
  • staraWartość = self();
  • self(wartość);
  • this.revert = funkcja() (
  • self(staraWartość);
  • this.commit = funkcja() (
  • staraWartość = self();
  • zwróć to;
  • Teraz mogę wywołać funkcję store, aby dodać tę funkcjonalność do modelu:

  • funkcja film(dane) (
  • // ...
  • // Nowy kod:
  • self.Title = ko.observable(data.Title).store();
  • self.Year = ko.observable(data.Year).store();
  • self.Rating = ko.observable(data.Rating).store();
  • self.Genre = ko.observable(data.Genre).store();
  • Ryż. Rysunek 13 przedstawia funkcje zapisu i anulowania w modelu widoku.

    Ryż. 13. Dodanie funkcji zapisu i anulowania

  • self.cancel = funkcja (element) (
  • cofnij zmiany (element);
  • pozycja.edycja(false);
  • self.save = funkcja (element) (
  • aplikacja.usługa.update(element).then(
  • funkcjonować()(
  • commitChanges(element);
  • funkcja (błąd) (
  • onError(błąd);
  • cofnij zmiany (element);
  • )).always(funkcja () (
  • pozycja.edycja(false);
  • funkcja commitChanges(element) (
  • for (var prop w elemencie) (
  • if (item.hasOwnProperty(prop) && item.commit) (
  • pozycja.zatwierdzenie();
  • funkcja revertChanges(element) (
  • for (var prop w elemencie) (
  • if (item.hasOwnProperty(prop) && item.revert) (
  • element.revert();
  • Tworzenie klienta WWW przy użyciu Ember

    Dla porównania napisałem kolejną wersję mojej aplikacji wykorzystując bibliotekę Ember.js.

    Aplikacja Ember rozpoczyna się od tabeli routingu, która definiuje nawigację użytkownika w aplikacji:

  • window.App = Ember.Application.create();
  • Aplikacja.Router.map(funkcja() (
  • this.route("około");
  • this.resource("gatunki", funkcja () (
  • this.route("filmy", ( ścieżka: "/:nazwa_gatunku" ));
  • Pierwsza linia kodu tworzy aplikację Ember. Wywołanie Router.map tworzy trzy trasy. Każda trasa pasuje do identyfikatora URI lub wzorca URI:

    /#/o /#/gatunki /#/gatunki/nazwa_gatunku

    Dla każdej trasy tworzysz szablon HTML, korzystając z biblioteki szablonów Handlebars.

    Ember posiada szablon najwyższego poziomu dla całej aplikacji. Ten szablon jest renderowany dla każdej trasy. Na ryc. Rysunek 14 przedstawia szablon aplikacji dla mojej aplikacji. Jak widać, ten szablon to w zasadzie kod HTML umieszczony w znaczniku skryptu z type="text/x-handlebars". Szablon zawiera specjalne znaczniki Handlebars w podwójnych nawiasach klamrowych: (( )). Ten znacznik służy temu samemu celowi, co atrybut wiązania danych w Knockout. Na przykład ((#linkTo)) tworzy łącze do trasy.

    Ryż. 14. Szablon kierownicy na poziomie aplikacji

  • ko.observable.fn.store = funkcja () (
  • var self = to;
  • var staraWartość = self();
  • var obserwowalny = ko.obliczony((
  • czytaj: funkcja() (
  • zwróć siebie();
  • napisz: funkcja (wartość) (
  • staraWartość = self();
  • self(wartość);
  • this.revert = funkcja() (
  • self(staraWartość);
  • this.commit = funkcja() (
  • staraWartość = self();
  • zwróć to;
  • Kino
  • ((wylot))
  • 2013 Mike'a Wassona

  • Załóżmy teraz, że użytkownik przechodzi do /#/about. Umożliwi to poruszanie się po trasie. Ember najpierw renderuje szablon aplikacji najwyższego poziomu, a następnie szablon about do szablonu aplikacji ((outlet)). Oto szablon dotyczący:

  • Aplikacja Filmy
  • Informacje o tej aplikacji...
  • Na ryc. Rysunek 15 pokazuje, jak szablon about jest renderowany w szablonie aplikacji.


    Ryż. 15. Renderowanie szablonu about

    Ponieważ każda trasa ma inny identyfikator URI, historia przeglądarki jest zapisywana. Użytkownik może nawigować za pomocą przycisku Wstecz, a także odświeżyć stronę bez utraty kontekstu lub zakładki i ponownie załadować tę samą stronę.

    Kontrolery i modele w Ember

    W Ember każda trasa ma model i kontroler. Model zawiera dane domeny. Kontroler pełni rolę proxy dla modelu i przechowuje wszystkie dane o stanie aplikacji dla widoku. (To nie to samo, co klasyczna definicja MVC. Pod pewnymi względami kontroler bardziej przypomina model widoku.)

    Tak zdefiniowałem model filmowy:

  • Aplikacja.Film = DS.Model.extend((
  • Tytuł: DS.attr(),
  • Gatunek: DS.attr(),
  • Rok: DS.attr(),
  • Ocena: DS.attr(),
  • Kontroler dziedziczy po Ember.ObjectController (rys. 16).

    Ryż. 16. Kontroler filmu dziedziczy po Ember.ObjectController

  • App.MovieController = Ember.ObjectController.extend((
  • isEditing: false,
  • działania: (
  • edycja: funkcja() (
  • this.set("jestedytowany", true);
  • zapisz: funkcja() (
  • ta.zawartość.zapisz();
  • this.set("jestedytowany", false);
  • anuluj: funkcja () (
  • this.set("jestedytowany", false);
  • this.content.rollback();
  • Dzieje się tu coś ciekawego. Po pierwsze, nie określiłem modelu w klasie kontrolera. Domyślnie trasa automatycznie ustawia model w kontrolerze. Po drugie, funkcje zapisu i anulowania wykorzystują możliwości transakcyjne wbudowane w klasę DS.Model. Aby cofnąć zmiany, po prostu wywołaj funkcję wycofania modelu.

    Ember wykorzystuje mnóstwo konwencji nazewnictwa do łączenia różnych komponentów. Trasa gatunków komunikuje się z GenresController, który renderuje szablon gatunków. Zasadniczo Ember automatycznie utworzy obiekt GenresController, jeśli go nie zdefiniowałeś. Można jednak zastąpić wszystko, co jest domyślnie dostępne.

    W mojej aplikacji skonfigurowałem trasę gatunków/filmów tak, aby korzystała z innego kontrolera, implementując hak renderTemplate. Tym samym z tego samego kontrolera może korzystać kilka tras (rys. 17).

    Ryż. 17. Wiele tras może mieć wspólnego kontrolera

  • App.GenresMoviesRoute = Ember.Route.extend((
  • serializować: funkcja (model) (
  • return ( nazwa_gatunku: model.get("nazwa") );
  • renderTemplate: funkcja() (
  • this.render((kontroler: „filmy” ));
  • afterModel: funkcja (gatunek) (
  • var kontroler = this.controllerFor("filmy");
  • var sklep = kontroler.sklep;
  • return store.findQuery("film", ( gatunek: gatunek.get("nazwa")))
  • .then(funkcja (dane) (
  • kontroler.set("model", dane);
  • Jedną z fajnych rzeczy w Emberze jest to, że można wiele zrobić przy użyciu bardzo małej ilości kodu. Moja przykładowa aplikacja składa się z około 110 linii kodu JavaScript. Ta wersja jest krótsza od wersji opartej na Knockout, a dodatkowo bez żadnego wysiłku dostałem obsługę historii przeglądarki. Z drugiej strony Ember to także bardzo kapryśny framework. Jeśli nie kodujesz w stylu Ember, prawdopodobnie wpadniesz w kłopoty. Zatem wybierając infrastrukturę, należy wziąć pod uwagę funkcjonalność, styl kodowania i stopień, w jakim ogólna architektura infrastruktury odpowiada Twoim wymaganiom.

    Gdzie dowiedzieć się więcej

    W tym artykule pokazałem, jak frameworki JavaScript ułatwiają tworzenie SPA. Po drodze opisałem niektóre typowe cechy tych bibliotek, w tym wiązanie danych, routing oraz wzorce MVC i MVVM. Aby dowiedzieć się więcej na temat tworzenia SPA przy użyciu ASP.NET, odwiedź stronę asp.net/single-page-application.

    Mike Wasson jest programistą i autorem tekstów technicznych w firmie Microsoft. Od wielu lat dokumentuję multimedialną część API Win32. Obecnie pisze o ASP.NET, ze szczególnym uwzględnieniem interfejsów API sieci Web. Można się z nim skontaktować pod adresem [e-mail chroniony].

    Dziękujemy ekspertowi firmy Microsoft Xinyang Qiu za zapoznanie się z tym artykułem.

    21 maja 2017 r

    Witryny jednostronicowe lub aplikacje jednostronicowe (SPA) są fajne. Ich główną zaletą jest to, że SPA jest szybsze i lepiej reaguje na działania użytkownika. Osiąga się to poprzez przeniesienie logiki pracy na stronę klienta i aktywną interakcję z serwerem poprzez ajax.

    Istnieje opinia, że ​​SPA to potężne aplikacje w Angularze lub Reactie, przenoszące tony danych w jakimś panelu sterowania lub w złożonej usłudze. I ogólnie rzecz biorąc, jest to prawdą. Jestem jednak przekonany, że pisanie jednostronicowych aplikacji ma sens nie tylko dla tego typu usług, ale także dla zwykłych witryn z wizytówkami firmowymi.

    Dlaczego jest to konieczne i jak to zrobić przy odrobinie wysiłku? Więcej na ten temat poniżej. Iść.

    Więc po co to rozpieszczanie?

    Najważniejsza jest szybkość pracy.

    Oczywiście tworząc jednostronicową witrynę wizytówkową napotkamy pewne problemy:

    • 1. Jak podejść, od czego zacząć?
    • 2. Jak sobie poradzić z historią przeglądarki za pomocą History API?
    • 3. Który framework lub bibliotekę powinienem studiować: Angular, React? A my nie znamy ani jednego...
    • 4. Jak zmusić wyszukiwarki do zaindeksowania witryny jednostronicowej?

    Odpowiedzi na te pytania:

    • 1. Przyjrzyjmy się temu w tym samym artykule, na przykładzie prostej strony internetowej
    • 2. Powiem Ci też poniżej, to kilkanaście linijek kodu
    • 3. Brak, wystarczy nam natywny JavaScript i jQuery jako asystent
    • 4. Następny artykuł z tej serii będzie dotyczył wyszukiwarek.

    Dlaczego bez reakcji kątowej?
    Oczywiście są to bardzo potrzebne tematy, polecam je przestudiować. Ale w naszym przykładzie nie będą one potrzebne; wystarczy minimalna znajomość JavaScript.

    One-pagery są tematem więcej niż jednego artykułu. Będzie to cały projekt, cykl artykułów składający się z co najmniej trzech części. A będzie poruszał różnorodne tematy. Ale pozwólcie, że wyjaśnię. Zbudujemy prosty panel administracyjny z interakcją z serwerem poprzez REST API (przynajmniej na samym początku). Na pierwszych lekcjach nasza jednostronicowa strona internetowa będzie zwykłą kilkunastostronicową wizytówką. Ale witryna będzie działać bez ponownego ładowania stron i zachwyci naszych użytkowników szybkością i responsywnością interfejsu.

    Pomysł na stronę, jak to działa

    Weźmy najpopularniejszy serwis korporacyjny: stronę główną, sekcję „O projekcie”, kontakty i blog. Sekcja Blog będzie zawierać kilka linków do stron wewnętrznych. Na każdej stronie dodamy trochę treści i umieścimy odsyłacze.

    Każda strona w witrynie zazwyczaj zawiera powtarzającą się treść. Dla nas będzie to nagłówek i menu. Zmienia się także główna treść strony. Zrobimy tak: załadujemy stronę tylko raz, a następnie klikając w linki będziemy dynamicznie ładować potrzebną treść za pomocą Ajaxa. Jednocześnie zmienimy tytuł strony w zakładce przeglądarki, adres URL w pasku adresu oraz zapamiętamy historię w przeglądarce, aby nawigacja po przyciskach Wstecz/Dalej przeglądarki działała.

    Treść każdej strony będzie przechowywana w oddzielnym pliku HTML.

    Od razu widać, z czym skończymy -

    Struktura terenu i prace przygotowawcze

    Struktura plików i folderów jest następująca. W katalogu głównym projektu znajduje się plik Index.php i .htaccess. Powiem ci później, dlaczego dokładnie php, a nie html. Folder css zawiera style w pliku main.css. Folder js zawiera bibliotekę jquery.js i główny plik aplikacji main.js. Folder stron zawiera pliki HTML z zawartością serwisu - po jednym na każdą stronę.

    Przygotowanie treści

    Zrobię stronę demonstracyjną na przykładzie mojego projektu webdevkin. Zestaw stron będzie wyglądał następująco:

    • — główna - Strona główna
    • — o — O projekcie
    • — blog - Blog
      • — sklep - Sklepy internetowe
      • — frontend — frontend
      • — mysql — baza danych MySql
      • — widżety - Widżety do osadzania
    • — prosty - Prosty projekt
    • — kontakty - Kontakty

    Odpowiednio folder stron będzie zawierał 9 plików HTML. Wszystkie znaczniki zawartości można znaleźć w formacie . Jako przykład podam zawartość tylko jednego pliku - simple.html

    Projekt Simple wyrósł z witryny blogowej. Ideą projektu jest stworzenie prostych i łatwych do osadzenia widżetów, które pomogą w interakcji z osobami odwiedzającymi Twoją witrynę. W tej chwili istnieje już widget ankiety, który można łatwo utworzyć i umieścić na dowolnej stronie internetowej.

    Jak widać nie ma tutaj head, body, html, script - jedynie znaczniki powiązane z konkretną stroną.

    indeks.php i .htaccess

    Dlaczego nie indeks.html?
    Faktem jest, że na naszej stronie będzie jedna fizyczna strona - indeks. Ale interesują nas również takie adresy, jak site.ru/about, site.ru/contacts itp. Jednak w katalogu głównym naszej witryny nie ma stron „O mnie” i „Kontakty”. Folder stron zawierający zestaw plików HTML nie jest pełnoprawnymi stronami, ale po prostu fragmentami kodu HTML wbudowanymi w ogólną strukturę.

    Dlatego, abyśmy podczas uzyskiwania dostępu do site.ru/about nie otrzymali 500, 403 i Bóg jeden wie, jakie inne błędy, musimy przekierować wszystkie przychodzące żądania do witryny na Index.php, który rozwiąże te żądania. Jednak na razie nasz plik Index.php jest zwykłym znacznikiem HTML bez ani jednej linii kodu PHP (ale to tylko na razie). A w .htaccess napiszemy co następuje. Rzadko będziesz musiał do tego wracać.

    RewriteEngine On Opcje +SymLinksIfOwnerMatch RewriteCond %(REQUEST_FILENAME) !-d RewriteCond %(REQUEST_FILENAME) !-f RewriteCond %(REQUEST_FILENAME) !-l RewriteRule ^(.+)$ indeks.php?q=$1

    Do momentu
    Kiedyś napisałem artykuł o prostej usłudze RESTful w natywnym PHP. Znajdziesz tam nieco więcej informacji na temat tej metody przekierowywania żądań.

    Nasz kod HTML będzie bardzo prosty. Style CSS/main.css są zawarte w nagłówku. W stopce znajdują się 2 pliki js: js/jquery.js i js/main.js. A w ciele będzie:

    Najpierw wyświetlamy menu. Następnie pojawia się tytuł strony. A poniżej pusty div z id=content (nie zwracajcie uwagi na style="" - kiedyś ten parser mnie wkurzy i go zastąpię). #content będzie dynamicznie ładować zawartość strony z plików page/*.html. Jeszcze nic ciekawego.

    Zwróć tylko uwagę na atrybuty data-menu i data-link="ajax" linków. Wprowadza się je, aby odróżnić linki nawigacyjne od zwykłych linków zewnętrznych, które również znajdą się na naszej stronie internetowej. data-link="ajax" oznacza, że ​​gdy klikniesz w ten link, przechwycimy standardowe zachowanie przeglądarki i weźmiemy pracę z linkiem w swoje ręce. A menu danych oznacza, która pozycja menu głównego zostanie podświetlona po kliknięciu tego łącza. Tutaj menu danych jest powielone z atrybutem href, ale możliwe są inne opcje. Przykładowo, gdy przejdziemy do sekcji frontendowej bloga, wskażemy data-menu="blog".

    2 przykłady dla jasności:

    simple.ru Strona główna simple.ru Style main.css

    Szybko przewińmy i skopiujmy i wklejmy najnudniejszą część – plik css/main.css.

    Treść ( pozycja: względna; rodzina czcionek: „Helvetica Neue Light”, „Helvetica Neue-Light”, „Helvetica Neue”, Calibri, Helvetica, Arial; rozmiar czcionki: 1em; grubość czcionki: 400; kolor: #333 ; ) a, a:visited ( kolor: steelblue; ) a:hover ( kolor: granatowy; ) .wrapper ( szerokość: 80%; margines: 0 10%; ) .spa-title (rozmiar czcionki: 1,2em; tekst - wyrównanie: do środka; ) menu ( margines u góry: 2em; dopełnienie: 0; wyrównanie tekstu: do środka; ) menu a ( display: inline-block; margines do prawej: 10px; dopełnienie: 5px 15px; dekoracja tekstu: brak ; ) menu a:hover, menu a.active ( kolor tła: stalowoniebieski; kolor: biały; ) .page-title ( wyrównanie tekstu: do środka; ) ul li (typ-stylu listy: okrąg; )

    Teraz najciekawsza część - kod JavaScript, który zamieni nasz zestaw pojedynczych plików w jednostronicową stronę internetową.

    JavaScript Ogólny kod i konfiguracje

    Ustawmy framework kodu js.

    Var app = (function() ( var config = (); var ui = (); // Funkcja powiązania zdarzenia _bindHandlers() ( // ... ) // Funkcja inicjalizacji aplikacji init() ( // ... _bindHandlers (); ) // Powrót poza return ( init: init ) ))(); // Uruchom aplikację $(document).ready(app.init);

    Mamy oddzielny moduł aplikacji, który uruchamia swoją funkcję inicjującą po załadowaniu strony. Dołączamy w nim procedury obsługi zdarzeń i wykonujemy trochę więcej kodu. Widzimy także 2 obiekty: config i ui. Wszystkie elementy domeny, które będą nam potrzebne w naszej pracy, zostaną zapisane w pamięci podręcznej interfejsu użytkownika.

    Var ui = ( $treść: $("treść"), $menu: $("#menu"), $pageTitle: $("#tytuł-strony"), $treść: $("#treść") );

    Potrzebujemy $menu do podświetlania poszczególnych pozycji menu, $pageTitle będzie zmieniane dynamicznie podczas poruszania się pomiędzy stronami, a $content będzie ładowany zawartością stron/plików*.html

    Ale konfiguracja wygląda bardziej interesująco.

    Var config = ( tytuł witryny: „Webdevkin SPA”, strona główna: „główna”, strony: ( główna: ( tytuł: „Główna”, menu: „główna” ), about: ( tytuł: „O projekcie”, menu: „ o " ), blog: ( tytuł: "Webdevkin-blog", menu: "blog"), prosty: ( tytuł: "Prosty projekt", menu: "prosty"), kontakty: ( tytuł: "Kontakty", menu : "kontakty" ), sklep: ( tytuł: "Sklepy internetowe", menu: "blog"), frontend: ( tytuł: "Artykuły o interfejsie", menu: "blog"), mysql: ( tytuł: "Baza danych Mysql ", menu: "blog" ), widżety: ( tytuł: "Osadzane widżety javascipt", menu: "blog" ) ) );

    siteTitle: "Webdevkin SPA" - tytuł strony, używany w kilku miejscach.
    mainPage: „main” - wskaż stronę początkową witryny, która otworzy się po wejściu na site.ru. To jest teraz strona główna, ale łatwo może Ci się przydać strona startowa, np. „O projekcie” – o.

    Najważniejszą rzeczą w całej konfiguracji jest obiekt Pages. Każde pole obiektu opisuje jedną stronę serwisu. Teraz potrzebujemy tylko 2 elementów: tytułu strony i menu, do którego należy ta strona. Klucze obiektu, czyli strony, odpowiadają nazwom plików w pages/*.html i atrybutom href w linkach wewnętrznych.

    Na koniec napiszemy kod, od którego wszystko zaczęliśmy. Możesz być zaskoczony, ale kodu, który bezpośrednio wykonuje pracę związaną z utrzymaniem witryny, jest znacznie mniej niż przygotowanie do jej napisania.

    Ładowanie treści za pomocą ajax. API historii

    Chodźmy po kolei. Popracujmy nad funkcją init, która zawiera powiązanie niezbędnych zdarzeń _bindHandlers

    // Funkcja powiązania zdarzenia _bindHandlers() ( ui.$body.on("click", "a", _navigate); window.onpopstate = _popState; )

    W pierwszej linii wyłapujemy kliknięcia w linki wewnętrzne a i wysyłamy je do funkcji _navigate. Teraz jesteśmy wreszcie przekonani, że potrzebne są osobne atrybuty data-link="ajax" :-)

    Następne okno.onpopstate = _popState;
    Z dokumentacji.
    Zdarzenie popstate jest wywoływane do obiektu window za każdym razem, gdy aktywny wpis historii zmienia się pomiędzy dwoma wpisami historii dla tego samego dokumentu.
    Mówiąc najprościej, jest to działanie przycisków Wstecz/Dalej w przeglądarce. Jak widzimy, natywne zachowanie przeglądarki również wymaga przechwycenia. Dlatego oddamy kontrolę funkcji _popState.

    Dla lepszego zrozumienia podam kod obu funkcji na raz

    // Kliknij funkcję łącza _navigate(e) ( e.stopPropagation(); e.preventDefault(); var page = $(e.target).attr("href"); _loadPage(page); history.pushState( ( strona: strona), "", strona); ) // Funkcja przycisków Wstecz/Dalej _popState(e) ( var page = (e.state && e.state.page) || config.mainPage; _loadPage(page); )

    Kiedy nastąpi wyraźne kliknięcie łącza _navigate, zatrzymujemy bulgotanie zdarzenia kliknięcia i anulujemy domyślne zachowanie przeglądarki (podążanie za linkiem). Następnie identyfikujemy stronę, którą chcemy załadować (rozumianą przez atrybut href) i wywołujemy nową funkcję _loadPage. Wykona całą główną pracę związaną z ładowaniem treści, zmianą tytułu i tak dalej. A na koniec za pomocą history.pushState dodajemy nowy wpis w historii przeglądarki. Tak, sami tworzymy historię przeglądarki. Następnie, gdy uznamy to za konieczne. I zapisujemy dane o załadowanej stronie do obiektu (strona: strona). Dane te przydadzą nam się w kolejnej funkcji _popState.

    W _popState pomysł jest podobny: szukamy żądanej strony i uruchamiamy tę samą _loadPage.

    Var page = (e.state && e.state.page) || config.mainPage;

    e.state && e.state.page - wyciąga dla nas stronę z obiektu historii, który ostrożnie zapisaliśmy w _navigate. Jeśli obiekt e.state nie jest dostępny (na przykład, kiedy po raz pierwszy odwiedziliśmy witrynę site.ru i nie mieliśmy jeszcze czasu na poruszanie się po niej), wówczas bierzemy stronę określoną jako główną w naszej konfiguracji - config. Strona główna.
    Szczerze mówiąc, funkcja history.pushState i fakt, że obiekt e.state z danymi zapisanymi w pushState jest dostępny w window.onpopstate, to wszystko, co musimy wiedzieć o API History. Jeśli chodzi o bardziej ciekawskich towarzyszy, nie mam wątpliwości, że googling pomoże ci znaleźć inne dobre sposoby pracy z historią przeglądarki.

    Nie będziemy angażować się w głębokie badania, ale napiszemy kod głównej funkcji _loadPage

    // Załaduj zawartość według funkcji strony _loadPage(strona) ( var url = "pages/" + strona + ".html", pageTitle = config.pages.title, menu = config.pages.menu; $.get(url, funkcja (html) ( document.title = pageTitle + " | " + config.siteTitle; ui.$menu.find("a").removeClass("active"); ui.$menu.find("a").addClass („aktywny”); ui.$pageTitle.html(pageTitle);

    Wygląda całkiem zwyczajnie. Najpierw tworzymy adres URL, czyli ścieżkę, z której pobierzemy kod HTML strony. Następnie wyciągamy tytuł strony i pozycję menu do wybrania z konfiguracji. Następnie pobieramy zawartość HTML strony poprzez banalny plik jQuery.get i wykonujemy szereg prostych czynności.

    a) Zaktualizuj tytuł strony
    b) W 2 liniach wybierz żądaną pozycję menu
    c) Zmień tytuł na samej stronie, w kodzie HTML
    d) Załaduj rzeczywistą zawartość HTML strony uzyskaną z adresu URL

    Prawie wszystko! Pozostała mała chwila. Jeśli teraz przejdziemy na przykład na stronę site.ru/blog i zaktualizujemy ją, to nie załaduje się blog, ale pusta strona. Ponieważ podczas inicjalizacji nie wywołujemy _loadPage. Aby to naprawić, musimy dodać kilka linii do funkcji init, która ostatecznie będzie wyglądać tak

    // Zainicjuj funkcję aplikacji init() ( var page = document.location.pathname.substr(1) || config.mainPage; _loadPage(page); _bindHandlers(); )

    To wszystko jest teraz pewne!

    Podsumujmy i przypomnijmy linki

    Napisaliśmy więc prostą, ale w pełni funkcjonalną, jednostronicową witrynę internetową, a także dowiedzieliśmy się trochę o działaniu History API. Szczerze mówiąc, czuję się jak reżyser złego filmu, który w 80% przypadków prowadzi do jakiegoś wspaniałego rezultatu, a na koniec wszystko okazuje się znacznie łatwiejsze, niż się spodziewano.

    Z jednej strony prawie cały kod to tylko przygotowanie, okablowanie, pisanie konfiguracji i inne nudne rzeczy. Ale naprawdę przydatny kod, który wykonuje rzeczywistą pracę, zajmuje 2 tuziny linii.

    Ale z drugiej strony konfiguracje pozwoliły nam stworzyć strukturę, którą można łatwo rozszerzyć podczas dodawania nowych stron. Ponadto w następnym artykule przekonamy się, jak ważna jest ta dość duża konfiguracja, gdy będziemy uczyć wyszukiwarki indeksowania naszej jednostronicowej witryny. Cóż, potrzebne są stylizacje, żeby wyglądać ładniej :-)

    Jest też osoba trzecia. Dla tych, którzy nie są zaznajomieni z witrynami jednostronicowymi, nie jest to wcale prosta sprawa. I myślę, że to wspaniale, gdy początkowo pozornie złożony temat, po szczegółowym rozważeniu, okazuje się całkowicie możliwy do rozwiązania i to bez większego wysiłku z naszej strony.

    Następnie nasza strona demonstracyjna będzie się stopniowo rozwijać. W kolejnym artykule zaczniemy przygotowywać witrynę do indeksowania przez wyszukiwarki, bo wiadomo, że strony jednostronicowe są bardzo słabo indeksowane, jeśli nie zostaną podjęte specjalne działania. Ale to już z kolejnych artykułów z tej serii.

    I mała ankieta

    Spodobał Ci się artykuł? Podziel się z przyjaciółmi!
    Czy ten artykuł był pomocny?
    Tak
    NIE
    Dziekuję za odpowiedź!
    Coś poszło nie tak i Twój głos nie został policzony.
    Dziękuję. Twoja wiadomość została wysłana
    Znalazłeś błąd w tekście?
    Wybierz, kliknij Ctrl + Enter a my wszystko naprawimy!
  • Ratować
  • Anulować
  • Edytować