6 września 2015 r

Któregoś dnia wpadłem na szalony pomysł napisania serii postów o różnych podejściach do organizacji kodu JavaScript. Pomysł ten zrodził się, gdy uczyłem się React.js do pracy i byłem zachwycony niektórymi pomysłami przedstawionymi przez jego autorów. Chciałem bardziej tego dotknąć, a ponieważ pisanie powitań z dokumentacji jest nudne, potrzebowałem jakiegoś pomysłu. Skoro zacząłem blogować na temat tworzenia stron internetowych, dlaczego nie stworzyć prostej, ale mniej lub bardziej zrozumiałej aplikacji przy użyciu różnych bibliotek i frameworków? I nie tylko reakcja, ale każda inna, do której może dotrzeć zły i zaogniony umysł. Jako aplikację testową wezmę prosty sklep internetowy z katalogiem i koszykiem. Sztuczka polega na tym, że kod zarówno katalogu, jak i koszyka będzie napisany w JavaScript. Wózek z przodu nie jest najlepszym rozwiązaniem przy realnych projektach, ale przy małych witrynach i do celów naukowych sprawdzi się dobrze. Nauka React zajmie trochę czasu, więc najpierw zabawię Cię artykułem, w którym opiszę proces tworzenia naszej aplikacji bez korzystania z bibliotek i frameworków, ale z wykorzystaniem modułów JavaScript. Moim głównym celem jest pokazanie różnych podejść do tworzenia aplikacji w JavaScript. Nie będę się zbytnio przejmować układem, zrobię układ za pomocą bootstrap, a mój główny nacisk zostanie położony na kod JavaScript. Będziemy manipulować DOM przy użyciu znanego, dobrego jquery. Podłączymy także podkreślenie do pracy z danymi i szablonami HTML. Dane do katalogu załadujemy z zewnętrznego pliku json, a koszyk zapiszemy w localStorage. Zacznijmy więc...

Pomysł zastosowania i schemat działania.

Sklep internetowy jest więc z przodu. Czego od niego chcemy? Zależy nam, aby możliwe było chociaż wyświetlenie katalogu produktów, dodanie ich do koszyka, obejrzenie tego koszyka, zmiana ilości znajdujących się w nim produktów oraz usunięcie tych dodanych omyłkowo, przeliczając koszt zamówienia. Dodatkowo dodamy magazyn danych do localStorage, aby po przeładowaniu strony nasz koszyk nie poszedł w zapomnienie.

Należy pamiętać, że nie jest to aplikacja jednostronicowa. Stworzymy 2 strony HTML, katalog i koszyk, ale posłużą one jedynie jako framework dla głównego kodu. Głównym kodem jest nadal JavaScript.

Bardziej szczegółowo funkcjonalność.

Menu główne - 2 przyciski, katalog i koszyk. W menu obok napisu „koszyk” wyświetlana jest ilość wybranych produktów. Strona indeksowa to strona główna sklepu, zwana także katalogiem. Ładujemy ich produkty z zewnętrznego pliku json. Produkty posiadają pola: id, nazwa, cena, img. Przy każdym produkcie znajduje się przycisk „Dodaj do koszyka”. Listę produktów przechowujemy w localStorage (identyfikator, nazwa, liczba, cena). Koszyk - tabela z wybranymi produktami. Wyświetlamy identyfikator i nazwę produktu, jego ilość i ilość. Poniżej tabeli podajemy łączną ilość wszystkich towarów. Zmieniając ilość towaru i usuwając go, zmieniamy wszystkie dane z tym związane. Katalog i koszyk zaprojektujemy jako osobne moduły.

Widzimy, z czym skończymy. Spróbuj dodać produkty do koszyka, przejść do niego, zmienić ilość i usunąć produkty i zobaczyć, jak sklep został zaprojektowany do działania. Możesz też od razu pobrać źródła z tego linku.

Struktura pliku

W katalogu głównym projektu umieścimy 2 pliki: indeks.html (katalog) i koszyk.html (koszyk). I kilka folderów: css, jest tam bootstrap.min.css i main.css - nasze style. Folder danych zawiera jeden plik towar.json – nasze produkty. Fonts przechowuje czcionki z ikon bootstrap. img - zdjęcia produktów i ładujący gif, który pokażemy odwiedzającym stronę podczas ładowania katalogu i koszyka. Folder js jest podzielony na 2 podfoldery: sprzedawca i moduły. sprzedawca zawiera potrzebne nam biblioteki: jquery i podkreślenie, a moduły zawierają moduły naszej aplikacji. Są ich tylko 3: main.js odpowiada za inicjalizację aplikacji, katalog służy do wyświetlania produktów, koszyk służy do obsługi koszyka.

Mała dygresja: Celowo nie wprowadziłem niepotrzebnej logiki do naszego projektu. Dobrą praktyką jest programowanie w oparciu o podejście MVC, dzielenie kodu na modele, kontrolery i widoki oraz dzielenie tych części na osobne pliki dla przejrzystości. Można długo dyskutować o słuszności stosowania tego podejścia do absolutnie wszystkich projektów, jednak w naszym konkretnym przykładzie odejdziemy od tego postulatu i umieścimy cały kod do zarządzania koszykiem w jednym pliku, a w jego ramach będziemy logicznie oddziel pracę z danymi od znaczników.

Zacznijmy rozwój.

Nie będę szczegółowo opisywał każdej linii kodu, zajęłoby to zbyt dużo miejsca i czasu. W artykule przyjrzymy się głównym punktom, a cały kod można wyświetlić w kodzie źródłowym pod powyższym linkiem. Kod ze szczegółowymi komentarzami.
Zaczynać.

Tworzymy znacznik.

Utwórzmy pliki indeks.html i cart.html w katalogu głównym naszego projektu. Każdy plik jest standardowym szablonem HTML5. W bloku nagłówkowym połączymy czcionkę Ubuntu z Google Fonts oraz 2 pliki css: bootstrap.min.css i nasze własne style main.css.

Webdevkina. Sklep internetowy. Javascript Na końcu strony, przed zamykającym tagiem body, umieścimy skrypty w następującej kolejności: Znacznik dla indeksu.html

Coś ciekawego: na stronie danych tagu body podajemy nazwę strony i element z id="total-cart-count", który będzie zawierał liczbę produktów dodanych do koszyka. Lista produktów katalogowych wyświetli się na liście id="towary". Podczas ładowania strony umieścimy nasz ładujący gif na liście, aby użytkownicy nie nudzili się czekaniem na załadowanie katalogu.

Znaczniki dla cart.html

Tutaj też nie ma nic specjalnego: pusta tabela koszyka, napis „total” i przycisk zamówienia (nie będziemy implementować jego funkcjonalności). Zawartość koszyka wyświetli się w tbody id="cart", teraz w tym miejscu znajduje się znany już gif. Uwaga: konwencje dotyczące kodu HTML i CSS.

Tworząc układ, zawsze staram się nie zapomnieć o kilku punktach i polecić je Tobie.
Po pierwsze: zawsze piszemy na zajęciach i tylko na zajęciach. Brak identyfikatorów w CSS. id jest potrzebny dla kodu JavaScript - aby szybko uzyskać dostęp do elementu DOM.
I po drugie: jeśli w kodzie js potrzebujemy dostępu do wielu elementów (wiele przycisków dodaje do koszyka), to do elementów przypisujemy klasy z przedrostkiem „js-”. I nie używamy tych „js” w kodzie CSS. Na początku te umowy wydają się niepotrzebne, ale korzyści szybko stają się wyraźniejsze w miarę rozwoju projektu. Lepiej od razu przyzwyczaić się do tego stylu, zwłaszcza, że ​​korzysta z niego całkiem sporo programistów.

Przygotowanie danych i znaczników do katalogu

Na początek utwórzmy plik do przechowywania naszych towarów: data/goods.json

[ ( "id": "1", "nazwa": "Notebook Lenovo", "cena": "18000", "img": "img/cars/notebook_lenovo.jpg" ), ( "id": "2" , "name": "Aparat Nikon", "cena": "25000", "img": "img/cars/camera_nikon.jpg" ), ( "id": "3", "nazwa": "Apple iPad" , "cena": "35000", "img": "img/cars/ipad.jpg" ), ( "id": "4", "nazwa": "Samsung Galaxy", "cena": "20000", "img": "img/cars/phone_galaxy.jpg" ), ( "id": "5", "nazwa": "SUPRA TV", "cena": "19000", "img": "img/samochody/ tv_supra.jpg" ) ] Jak widać, jest to zwykła tablica json z czterema potrzebnymi nam polami. Przejdźmy teraz do tworzenia katalogu. Zanim jednak zaczniemy pisać kod js, będziemy musieli napisać więcej znaczników, aby wyświetlić indywidualny produkt. Będziemy używać szablonów kodu HTML biblioteki podkreśleń do dynamicznego generowania poszczególnych produktów. Jeśli nie znasz szablonów podkreśleń, mam . Nie będę się nad tym rozwodzić, ale po prostu podam kod szablonu, zwłaszcza, że ​​jest on dość banalny i nie wymaga długich dyskusji: Co się dzieje w tym kodzie? Szablon podkreślenia to zwykły ciąg znaków, w który podstawiane są wymagane dane. Jest to dobry sposób na oddzielenie logiki i danych od prezentacji. Cała idea szablonów polega na tym, że nie wiemy, w jaki sposób dane są pozyskiwane, ale wiemy, jak powinny być wyświetlane. W naszym przykładzie wprowadzamy tablicę towarów towary (z pliku Goods.json), iterujemy po wszystkich towarach w pętli, korzystając z każdej funkcji biblioteki podkreśleń, a dla każdego produktu wyświetlamy własny znacznik, podstawiając produkt identyfikator, nazwa, zdjęcie i cena we właściwych miejscach. Zwróć uwagę na atrybuty daty przycisku „Dodaj do koszyka”, zostaną one wykorzystane w przyszłości. Powyższy kod umieścimy w treści pliku Index.html. Następnie zobaczymy, jak połączyć dane i nasz szablon podkreślenia.

Napisanie modułu katalogu js

Kod pliku Catalog.js będzie bardzo krótki

„użyj ściśle”; // Moduł katalogu var katalog = (function($) ( // Zainicjuj funkcję modułu init() ( _render(); ) // Renderuj funkcję katalogu _render() ( var szablon = _.template($("#catalog -template ").html()), $towary = $("#towary"); $.getJSON("dane/towary.json", funkcja(dane) ( $towary.html(template((towary: dane) )) ; )); ) // Eksportuj poza return ( init: init ) ))(jQuery); Tutaj, korzystając z domknięcia, deklarujemy zmienną modułu katalogu, piszemy funkcję init, która wywołuje najciekawszą dla nas funkcję _render i eksportujemy init na zewnątrz, umożliwiając jednocześnie wywołanie Catalog.init() z innych modułów aplikacji. W rzeczywistości można obejść się bez dodatkowej funkcji init, ale dla zachowania spójności zawsze lepiej jest zadeklarować publiczną funkcję init we wszystkich modułach. W tym przypadku funkcja _render zaczyna się od znaku _, co oznacza, że ​​funkcja ta ma charakter prywatny i nie powinna wychodzić poza granice modułu. Stosując takie podejście, widzimy już w kodzie modułu, co jest wykorzystywane w innych modułach, a co jest przeznaczone wyłącznie do użytku wewnętrznego. Rodzaj enkapsulacji kodu, jak w OOP.

Przyjrzyjmy się funkcji _render. Najpierw deklarujemy zmienną template = _.template($("#catalog-template").html()).
_.template to funkcja podkreślenia, która renderuje znaczniki HTML przy użyciu szablonu HTML i jego danych.
$("#catalog-template").html() - zawartość szablonu, tj. tylko sznurek. $.getJSON odbiera dane z pliku zewnętrznego i przekazuje naszą tablicę produktów do wywołania zwrotnego. Wyrażenie template((towary: dane)) oznacza, że ​​przekazujemy obiekt z danymi do funkcji szablonu i na jego podstawie generujemy ciąg HTML. Ten ciąg znaków jest wstawiany na stronę za pomocą $goods.html(htmlString). Teraz wystarczy wywołać funkcję Catalog.init(), aby załadować katalog na stronę Index.html

Moduł koszyka

Wreszcie dochodzimy do najciekawszej części naszego projektu – koszyka. Nasz moduł zostanie podzielony na 3 logiczne części:

  • 1 - logika pracy z danymi
  • 2 - praca ze zdarzeniami DOM
  • 3 - ogólne funkcje inicjalizacji i konfiguracji
Tak będzie wyglądał szablon modułu: „use strict”; // Moduł koszyka var cart = (function($) ( var cartData, // dane koszyka - tablica obiektów opts = (); // ustawienia modułu // Inicjalizacja funkcji modułu init(options) ( _initOptions(options); // Pobieranie danych // Renderuj koszyk _bindHandlers(); ) // Inicjuj funkcję ustawień _initOptions(options) ( // kod ) // Funkcja dołączania zdarzeń _bindHandlers() ( // kod ) // Funkcje do pracy z danymi / / Funkcje renderujące // Funkcje - obsługa zdarzeń // Eksportuj zewnętrzny powrót ( init: init, // funkcje do pracy z danymi ) ))(jQuery); Przeanalizujmy nasze przygotowania. Dla całego modułu dostępne są 2 zmienne globalne: dane koszyka i zestaw parametrów. Zestaw ten zawiera ustawienia modułu takie jak nazwy klas i atrybuty dat, elementy identyfikacyjne ilości towaru i łącznej kwoty zamówienia, klasy dla przycisków dodawania, usuwania, zmiany ilości i inne. Przyjrzyjmy się temu bardziej szczegółowo poniżej. Główną funkcją jest inicjalizacja modułu. Tylko to zostanie wywołane na zewnątrz modułu, reszta jest ukryta w implementacji koszyka. Moduł inicjuje się w następującej kolejności: przypisuje się opcje modułu, pobiera dane do koszyka z localStorage, renderuje sam koszyk, liczbę produktów i całkowitą kwotę zamówienia, a na koniec wiążemy procedury obsługi ze zdarzeniami DOM. Uwaga: jeśli nie stosowałeś wcześniej takiego podejścia do oddzielania danych od znaczników, zdziwisz się, o ile ciekawsze jest pisanie kodu przetwarzającego dane osobno i wtedy łatwiej jest dołączać zdarzenia do przycisków. Zademonstrujemy to później.

Pewnie zauważyłeś, że eksportuję nie tylko init, ale także wszystkie funkcje związane z przetwarzaniem danych. Dokonano tego w celu ułatwienia testowania kodu. Jak przeprowadzane są testy? Istnieją 2 sposoby: testy ręczne i jednostkowe. Podczas ręcznego testowania wywołujemy funkcje modułu w konsoli przeglądarki i od razu widzimy wynik. Przykładowo wywołując cart.add((id: 1, nazwa: "notebook", cena: 30000, liczba: 2)), możemy od razu zobaczyć zmiany w konsoli i upewnić się, że dane rzeczywiście zostały dodane ( albo coś poszło nie tak). Oddzieliliśmy logikę pracy z danymi od innych funkcji i zobaczyliśmy, że testowanie w ten sposób jest o wiele przyjemniejsze niż klikanie przycisków i sprawdzanie zawartości localStorage po każdym kliknięciu. Drugi sposób podpowie nam się sam, gdy znudzi nam się wpisywanie poleceń w konsoli i w końcu wymyślimy jednostkowe testowanie kodu. Napiszę o tym w jednym z nadchodzących artykułów.

AKTUALIZACJA: Dla zainteresowanych testami jednostkowymi ukazał się artykuł: testy jednostkowe z przodu czy nauka jasmine.js. Pokazuje jak przetestować kod korzystając z naszego koszyka korzystając z popularnej biblioteki jasmine.js.

Pisanie funkcji przetwarzających dane

W sumie napiszemy 11 funkcji:

  • 1. updateData - zaktualizuj dane z localStorage, zapisz zawartość do zmiennej cartData
  • 2. getData - zwróć dane
  • 3. saveData - zapisz koszyk w localStorage
  • 4. clearData - wyczyść koszyk
  • 5. getById - wyszukaj pozycję w koszyku według identyfikatora produktu
  • 6. dodaj - dodaj produkt do koszyka
  • 7. usuń - usuń przedmiot z koszyka
  • 8. zmieńCount - zmień ilość
  • 9. getCount - zwraca liczbę unikalnych pozycji w koszyku
  • 10. getCountAll - zwraca liczbę wszystkich pozycji w koszyku
  • 11. getSumma - zwróć całą kwotę zamówienia
Kod wszystkich funkcji jest dość prosty, składa się z kilku linijek, więc wymienię wszystkie funkcje na raz. Podczas przetwarzania stosowane są metody podkreślenia. Jeśli jeszcze nie znasz tej biblioteki, gorąco polecam ją sprawdzić. Nie bez powodu nazywany jest „szwajcarskim nożem programisty JavaScript”. Szybkie przestudiowanie oficjalnej dokumentacji (dostępnej w języku rosyjskim) zajmie trochę czasu, ale przyniesie zauważalne korzyści. Pełny kod do pracy z danymi // Funkcja pobierania danych updateData() ( cartData = JSON.parse(localStorage.getItem("koszyk")) || ; powrót cartData; ) // Funkcja zwrotu danych getData() ( powrót cartData; ) / / Zapisz dane w funkcji localStorage saveData() ( localStorage.setItem("koszyk", JSON.stringify(cartData)); return cartData; ) // Wyczyść funkcję danych clearData() ( cartData = ; saveData(); return cartData; ) // Wyszukiwanie obiektu w kolekcji CartData według funkcji id getById(id) ( return _.findWhere(cartData, (id: id)); ) // Dodanie produktu do funkcji kolekcji add(item) ( var oldItem; updateData(); oldItem = getById(item.id); if(!oldItem) ( cartData.push(item); ) else ( oldItem.count = oldItem.count + item.count; ) saveData(); return item; ) // Usuwanie elementu z kolekcji funkcja Remove(id) ( updateData(); cartData = _.reject(cartData, funkcja(item) ( return item.id === id; )); saveData(); return cartData; ) // Zmiana ilości towarów w kolekcjach funkcja ChangeCount(id, delta) ( var item; Uaktualnij dane(); pozycja = getById(id); if(item) ( item.count = item.count + delta; if (item.count

Ciekawostką jest to, że każda funkcja zwraca jakieś dane: cały koszyk, dodany produkt czy łączną kwotę. Nie wszystkie zwrócone dane są wykorzystywane w module, ale wszystkie ułatwiają testowanie. Widzimy również, że w localStorage przechowujemy serializowaną tablicę produktów. Funkcja dodawania stawia warunek: jeżeli dodamy towar, który już znajduje się w koszyku, to nie powstaje duplikat artykułu, lecz zwiększa się ilość już istniejącego. Gdy ilość danego produktu spadnie do zera, zostaje on usunięty z koszyka.

Inicjowanie ustawień. Ustawienia domyślne.

Zanim napiszemy funkcje renderujące i procedury obsługi zdarzeń, cofnijmy się trochę i przyjrzyjmy się inicjowaniu ustawień modułu. Funkcja _initOptions skopiuje do zmiennej opts wszystkie ustawienia przekazane do modułu koszyka podczas jego tworzenia.

// Zainicjuj funkcję ustawień _initOptions(options) ( var defaultOptions = ( renderCartOnInit: true, // czy renderować koszyk podczas inicjalizacji renderMenuCartOnInit: true, // czy renderować liczbę produktów w menu podczas inicjalizacji elAddToCart: „. js-add-to-cart ", // selektor przycisku dodaj do koszyka attrId: "data-id", // atrybut daty dla identyfikatora produktu attrName: "data-name", // atrybut daty dla nazwy produktu attrPrice: "data-price", // atrybut daty ceny produktu attrDelta: "data-delta", // atrybut daty pokazujący o ile zmienić ilość produktu w koszyku (-1 i 1) elCart: " #cart", // selektor zawartości koszyka elTotalCartCount: "#total-cart-count", // selektor liczby artykułów w koszyku elTotalCartSumma: "#total-cart-summa", // selektor całkowitego zamówienia ilość elCartItem: ".js-cart-item", // selektor dla pojedynczej pozycji w koszyku elCartCount: ".js-count", // selektor dla ilości pojedynczego produktu elCartSumma: ".js-summa", // selektor ilości pojedynczego produktu elChangeCount: ".js-change-count", // selektor przycisków zmiany ilości elRemoveFromCart: ".js-remove-from-cart", // selektor przycisku usuwania z koszyka elOrder: "#order" // selektor przycisku kasy ) _.defaults(options || (), opcje domyślne); opts = _.clone(opcje); ) Najpierw deklarujemy ustawienia domyślne, a następnie „sklejamy” je danymi pochodzącymi z zewnątrz. W przypadku małej aplikacji takiej jak nasza nie było konieczności implementowania możliwości dostosowania modułu. Ale ten niewielki wzrost kodu daje nam większą elastyczność podczas przenoszenia tego modułu do innego projektu.

Renderowanie koszyka i szablon HTML

Najpierw utwórzmy szablon wyświetlania koszyka i umieśćmy go w sekcji body pliku cart.html.

Wszystko tutaj jest znane z podobnej funkcjonalności w katalogu. W atrybutach danych umieszczamy id produktów, aby było jasne, z którymi aktualnie współpracujemy. Atrybut data-delta pokazuje, czy po kliknięciu tego przycisku zwiększyć, czy zmniejszyć ilość produktu.

Funkcje renderowania. // Renderuj funkcję koszyka renderCart() ( var szablon = _.template($("#cart-template").html()), data = ( towary: cartData ); $(opts.elCart).html(template ( dane)); renderTotalCartSumma(); ) // Renderuj liczbę produktów w funkcji menu renderMenuCart() ( var countAll = getCountAll(); $(opts.elTotalCartCount).html(countAll !== 0 ? countAll: " "); ) // Renderuje funkcję całkowitej sumy towarów renderTotalCartSumma() ( $(opts.elTotalCartSumma.html(getSumma()); ) Operacje na DOM są tradycyjnie trudne, więc wyrenderujemy cały koszyk, ale kiedy generując ilość i ilość, będziemy konkretnie odnosić się do elementów. Osoby obsługujące zdarzenia.

Zbliżamy się do końca...

Napiszmy funkcję pomocniczą pobierającą element koszyka po jego identyfikatorze. Przyda nam się to przy zmianie ilości i kasowaniu towaru

// Wyszukaj produkt w koszyku według funkcji id findCartElemById(id) ( return $(opts.elCartItem + "[" + opts.attrId + "=""+id+""]"); ) Linia wygląda przerażająco, ale sens sprowadza się do wyszukania takiego elementu $(.js-cart-item").

W sumie będziemy mieli 4 moduły obsługi kliknięć: dodanie do koszyka, zmiana ilości, usunięcie i złożenie zamówienia. Spójrzmy:

// Dodaj do koszyka funkcję _onClickAddBtn() ( $("body").on("click", opts.elAddToCart, funkcja(e) ( var $this = $(this); add(( id: +$this. attr(opts.attrId), nazwa: $this.attr(opts.attrName), cena: +$this.attr(opts.attrPrice), liczba: 1 )); renderMenuCart(); alert("Pozycja dodana do koszyka" ); )); ) // Zmień liczbę pozycji w koszyku funkcja _onClickChangeCountInCart() ( $("body").on("click", opts.elChangeCount, funkcja(e) ( var $this = $(this ), id = +$this.attr(opts.attrId), delta = +$this.attr(opts.attrDelta), $cartElem = findCartElemById(id), cartItem =changeCount(id, delta); if (cartItem.count ) ( $ CartElem.find(opts.elCartCount).html(cartItem.count); $cartElem.find(opts.elCartSumma).html(cartItem.count * cartItem.price); ) else ( $cartElem.remove(); ) renderMenuCart( ); renderTotalCartSumma(); )); ) // Usuń produkt z koszyka funkcja _onClickRemoveFromCart() ( $("body").on("kliknij", opts.elRemoveFromCart, funkcja(e) ( if( !confirm("Usunąć artykuł z koszyka?")) return false; var $this = $(to), id = +$this.attr(opts.attrId), $cartElem = findCartElemById(id); usuń(id); $koszykElem.usuń(); renderMenuCart(); renderTotalCartSumma(); )); ) // Złóż zamówienie funkcja _onClickOrder() ( $("body").on("click", opts.elOrder,function(e) ( // Pozwolę Ci napisać kod umożliwiający złożenie zamówienia i przesłanie danych do serwera sam alert("Złóż zamówienie :-)"); )); )

Na notatce. Stosując tak prostą sztuczkę, można znacznie zmniejszyć kod związany z renderowaniem i zawieszaniem zdarzeń. Łączymy kod renderujący koszyk, ilość i kwotę w jedną funkcję renderującą i wywołujemy ją po wszelkich manipulacjach z koszykiem. Oznacza to, że w każdym przypadku schemat wygląda następująco: wywołali wymaganą metodę przetwarzania danych - WSZYSTKO zostało wyrenderowane. Pozbywamy się wtedy kontroli typu „czy produkt został usunięty z koszyka po zmniejszeniu jego ilości” i wywoływania kilku funkcji renderujących zamiast jednej. W przypadku małych projektów jest to uzasadnione, jednak gdy Twoja aplikacja zawiera mnóstwo widżetów, skomplikowany układ i dane będą odbierane nie tylko poprzez kliknięcia użytkownika, ale także online z różnych źródeł, przerysowanie całej zawartości strony negatywnie wpłynie na wydajność przeglądarki. Dlatego nawet w naszym prostym przypadku wybrałem nieco bardziej skomplikowany, ale bardziej poprawny schemat.

Złożenie modułu koszyka w jedną całość

Główny kod został już napisany, pozostaje nam jeszcze napisać funkcję inicjującą koszyk i powiązującą obsługę zdarzeń. Przejdźmy od czegoś przeciwnego, handlerzy:

// Dołączamy funkcję zdarzeń _bindHandlers() ( _onClickAddBtn(); _onClickChangeCountInCart(); _onClickRemoveFromCart(); _onClickOrder(); ) Myślę, że tutaj bez większego wyjaśnienia zbieramy wcześniej napisane funkcje w pęczek. Inicjalizacja: // Inicjalizacja funkcji modułu init(options) ( _initOptions(options); updateData(); if (opts.renderCartOnInit) ( renderCart(); ) if (opts.renderMenuCartOnInit) ( renderMenuCart(); ) _bindHandlers(); ) Dlaczego wprowadziliśmy osobne ustawienia dla renderCartOnInit i opts.renderMenuCartOnInit? Po prostu dlatego, że na stronie katalogu musimy zainicjować koszyk (w menu wyświetlamy liczbę dodanych produktów), ale nie musimy go renderować. Aby nie komplikować logiki niepotrzebnymi kontrolami, rozdzieliliśmy te opcje.

Pełny kod koszyka

Przyjrzeliśmy się już kodowi całego koszyka w artykule, ale żeby jeszcze raz o tym pamiętać, oto cały moduł w pliku cart.js.

Główny moduł aplikacji

Prawdopodobnie nawet najbardziej uważny czytelnik jest już zmęczony czytaniem listów, dlatego spieszę z dokończeniem mojego traktatu.
Plik main.js to moduł główny, uruchomienie aplikacji, moduł królewski.

„użyj ściśle”; // Moduł aplikacji var app = (function($) ( var $body = $("body"), page = $body.data("page"), options = ( elAddToCart: ".js-add-to-cart ", attrId: "data-id", attrName: "data-name", attrPrice: "data-cena", attrDelta: "data-delta", elCart: "#cart", elTotalCartCount: "#total-cart-count ", elTotalCartSumma: "#total-summa-koszyka", elCartItem: ".js-cart-item", elCartCount: ".js-count", elCartSumma: ".js-summa", elChangeCount: ".js-change- count", elRemoveFromCart: ".js-remove-from-cart", elOrder: "#order" ), optionsCatalog = _.extend(( renderCartOnInit: false, renderMenuCartOnInit: true ), opcje), OptionsCart = _.extend(( renderCartOnInit: true, renderMenuCartOnInit: true ), opcje); funkcja init() ( if (strona === „katalog”) ( katalog.init(); cart.init(optionsCatalog); ) if (strona === „koszyk ") ( cart.init(optionsCart); ) ) return ( init: init ) ))(jQuery); jQuery(dokument).ready(app.init); Pomysł jest taki: deklarujemy moduł główny, ustawienia aplikacji (w naszym przypadku powielają one opcje domyślne), definiujemy aktualne ustawienia modułu strony i koszyka dla bieżącej strony i na koniec inicjujemy niezbędne moduły. Wszystko to uruchamia magiczna linia jQuery(document).ready(app.init);

Podsumujmy.

Napisaliśmy więc małą aplikację dla prostego sklepu internetowego z katalogiem i koszykiem.

AKTUALIZACJA: W związku z dużą popularnością artykułu i ogólnym zainteresowaniem tematyką sklepów internetowych, nagrano i opublikowano kontynuację artykułu: Implementacja składania zamówienia w sklepie internetowym na kliencie i serwerze. Obejmuje pełen cykl zbierania danych o kliencie, złożenie formularza zamówienia, wysłanie żądania Ajax do serwera, utworzenie tabel w bazie danych i dodanie tych samych danych, a także wysłanie listów z zamówieniem. Jak zwykle wszystko z przykładami. Źródła zostały zaktualizowane. Składanie zamówień jest zintegrowane z katalogiem i koszykiem omawianym w tym artykule. Wygląda jak kompletna aplikacja, gotowa do użycia.
Kolejna aktualizacja: gotowy jest artykuł o dodaniu metody dostawy do sklepu internetowego. Przeczytaj tutaj

Choć głównym celem było zademonstrowanie modułowego podejścia przy tworzeniu w JavaScript i oddzielenie logiki od prezentacji, moduł koszyka okazał się całkiem samowystarczalny i niezależny. W razie potrzeby możemy uwzględnić go w innych projektach. Mamy tylko 2 zależności modułów: jquery i podkreślenie. Choć sądzę, że osoby znające obie biblioteki dodają je do niemal każdego swojego projektu.

Wiele punktów w naszej aplikacji jest dość kontrowersyjnych. Nie ma ścisłego rozdzielenia logiki i prezentacji, funkcje te są połączone w jeden moduł. Ponadto szablony podkreśleń są wbudowane bezpośrednio w kod strony, co również nie jest najlepszą praktyką; należy je umieścić w oddzielnych plikach. Celowo nie skomplikowałem konstrukcji. W artykule przyjrzałem się przykładowi stworzenia kodu, który z jednej strony jest na tyle modułowy, że można go wygodnie testować, konserwować w przyszłości czy wydobywać pewne pomysły na przyszłe aplikacje, ale z drugiej strony nie tak skomplikowane, że zrozumienie zajmuje zbyt dużo czasu. Ostatecznie tworzone są biblioteki i frameworki do poważnego rozwoju JavaScriptu i prędzej czy później wszyscy dochodzimy do wniosku, że musimy je poznać i przestudiować. Backbone, Angular, Ember, React, jest ich naprawdę sporo i ciągle pojawiają się nowe. Im więcej studiujemy i dowiadujemy się o różnych podejściach, tym szersze są nasze horyzonty i tym większy wybór będziemy mieli.

Próbuję utworzyć prosty koszyk PHP z cenami, produktami, rejestracją i obszarem kasy. Przeszukałem Google w poszukiwaniu samouczków, ale wszystkie dotyczą języka SQL, który nie jest jeszcze w zasięgu moich umiejętności. Czy ktoś ma przykłady lub inne zasoby samouczka, które można uznać za początkującego PHP?

Ponownie próbuję stworzyć prosty koszyk na zakupy w PHP (bez SQL) przy użyciu tablic dla produktów, funkcji do różnych zadań programu, sprawdzania poprawności formularzy, plików cookie/sesji zapewniających ciągłość koszyka, plików szablonów i wiadomości e-mail z potwierdzeniem/potwierdzeniem.

Z góry dziękuje za twoją pomoc!

3 odpowiedzi

Zamiast krytykować, dlaczego nie po prostu pomóc? Hipokryzja, ale co tam. Pamiętaj, że bez bazy danych SQL nie możesz się „zarejestrować”, ale możesz mieć tymczasowe nazwy użytkowników i hasła.

Stwórzmy więc twoją pseudo bazę danych sql za pomocą php.

Potrzebujemy tabeli do przechowywania nazw użytkowników i haseł do Twojego konta.

Teraz potrzebujemy stołu do przechowywania produktów

Mamy więc „tabelę” naszych produktów i „tabelę kont”. Teraz bardziej złożona część, czyli utworzenie systemu, który pobiera wszystkie te informacje, wyświetla je, umożliwia logowanie i wylogowywanie się oraz śledzi produkty, które masz w koszyku.