„Thinking in AngularJS”, jeśli mam doświadczenie w jQuery? [Zamknięte]

4514

Załóżmy, że znam się na tworzeniu aplikacji po stronie klienta w jQuery , ale teraz chciałbym zacząć używać AngularJS . Czy potrafisz opisać niezbędną zmianę paradygmatu? Oto kilka pytań, które mogą pomóc w sformułowaniu odpowiedzi:

  • Jak inaczej projektować i projektować aplikacje internetowe po stronie klienta? Jaka jest największa różnica?
  • Co powinienem przestać robić / używać; Co powinienem zacząć robić / używać?
  • Czy są jakieś względy / ograniczenia po stronie serwera?

Nie szukam szczegółowego porównania między jQueryi AngularJS.

Mark Rajcok
źródło
Dla tych, którzy znają „ASP.NET MVC” lub „RoR” - pomyśl o Angular jako o „MVC po stronie klienta” i to wszystko.
Serge Shultz

Odpowiedzi:

7178

1. Nie projektuj swojej strony, a następnie zmieniaj ją za pomocą manipulacji DOM

W jQuery projektujesz stronę, a następnie czynisz ją dynamiczną. Wynika to z faktu, że jQuery został zaprojektowany z myślą o rozszerzeniu i wyrósł niesamowicie z tego prostego założenia.

Ale w AngularJS musisz zacząć od podstaw z myślą o swojej architekturze. Zamiast zaczynać od myślenia: „Mam ten element DOM i chcę, aby działał w X”, musisz zacząć od tego, co chcesz osiągnąć, a następnie zająć się projektowaniem aplikacji, a następnie projektowaniem widoku.

2. Nie rozszerzaj jQuery za pomocą AngularJS

Podobnie, nie zaczynaj od pomysłu, że jQuery robi X, Y i Z, więc po prostu dodam AngularJS do tego dla modeli i kontrolerów. To naprawdę kuszące, kiedy dopiero zaczynasz, dlatego zawsze zalecam, aby nowi programiści AngularJS w ogóle nie używali jQuery, przynajmniej dopóki nie przyzwyczają się do robienia rzeczy w „Angular Way”.

Widziałem wielu programistów tutaj i na liście mailingowej tworzących te skomplikowane rozwiązania z wtyczkami jQuery zawierającymi 150 lub 200 wierszy kodu, które następnie przyklejają do AngularJS z kolekcją wywołań zwrotnych i $applys, które są mylące i zawiłe; ale w końcu to działa! Problem polega na tym, że w większości przypadków wtyczka jQuery może zostać przepisana w AngularJS w ułamku kodu, gdzie nagle wszystko staje się zrozumiałe i proste.

Najważniejsze jest to: podczas rozwiązywania najpierw „pomyśl w AngularJS”; jeśli nie możesz znaleźć rozwiązania, zapytaj społeczność; jeśli po tym wszystkim, że nie ma prostego rozwiązania, następnie czuć się swobodnie dotrzeć do jQuery. Ale nie pozwól, aby jQuery stało się kulą, bo nigdy nie opanujesz AngularJS.

3. Zawsze myśl w kategoriach architektury

Najpierw wiedz, że aplikacje jednostronicowe to aplikacje . To nie są strony internetowe. Musimy więc myśleć podobnie jak programista po stronie serwera oprócz myślenia jak programista po stronie klienta. Musimy zastanowić się, jak podzielić naszą aplikację na poszczególne, rozszerzalne, testowalne komponenty.

Więc jak to robisz? Jak myślisz „w AngularJS”? Oto kilka ogólnych zasad, w przeciwieństwie do jQuery.

Widok jest „oficjalnym zapisem”

W jQuery programowo zmieniamy widok. Możemy zdefiniować menu rozwijane jako ul:

<ul class="main-menu">
    <li class="active">
        <a href="#/home">Home</a>
    </li>
    <li>
        <a href="#/menu1">Menu 1</a>
        <ul>
            <li><a href="#/sm1">Submenu 1</a></li>
            <li><a href="#/sm2">Submenu 2</a></li>
            <li><a href="#/sm3">Submenu 3</a></li>
        </ul>
    </li>
    <li>
        <a href="#/home">Menu 2</a>
    </li>
</ul>

W jQuery, w naszej logice aplikacji, aktywowalibyśmy go za pomocą czegoś takiego:

$('.main-menu').dropdownMenu();

Kiedy patrzymy tylko na widok, nie jest od razu oczywiste, że jest tu jakaś funkcjonalność. W przypadku małych aplikacji to w porządku. Ale w przypadku nietrywialnych aplikacji sprawy szybko stają się mylące i trudne do utrzymania.

Jednak w AngularJS widok jest oficjalnym zapisem funkcji opartych na widoku. ulZamiast tego nasza deklaracja wyglądałaby następująco:

<ul class="main-menu" dropdown-menu>
    ...
</ul>

Te dwie rzeczy robią to samo, ale w wersji AngularJS każdy, kto patrzy na szablon, wie, co się stanie. Za każdym razem, gdy dołącza nowy członek zespołu programistów, może na to spojrzeć, a następnie wiedzieć, że działa na nim dyrektywa dropdownMenu; nie musi intuicyjnie podawać poprawnej odpowiedzi ani przeglądać żadnego kodu. Widok powiedział nam, co miało się stać. Dużo czystsze.

Programiści nowi w AngularJS często zadają pytanie: jak znaleźć wszystkie linki określonego rodzaju i dodać do nich dyrektywę. Deweloper jest zawsze oszołomiony, kiedy odpowiadamy: nie. Ale powodem, dla którego tego nie robisz, jest to, że jest to w połowie jQuery, w połowie AngularJS i nic dobrego. Problem polega na tym, że programista próbuje „zrobić jQuery” w kontekście AngularJS. To nigdy nie zadziała dobrze. Widok jest oficjalnym zapisem. Poza dyrektywą (więcej na ten temat poniżej) nigdy nie zmienisz DOM. Dyrektywy są stosowane w widoku , więc zamiar jest jasny.

Pamiętaj: nie projektuj, a następnie zaznacz. Musisz zaprojektować, a następnie zaprojektować.

Wiązanie danych

Jest to zdecydowanie jedna z najbardziej niesamowitych funkcji AngularJS i eliminuje potrzebę wykonywania rodzajów manipulacji DOM, o których wspomniałem w poprzedniej sekcji. AngularJS automatycznie zaktualizuje twój widok, więc nie musisz! W jQuery reagujemy na zdarzenia, a następnie aktualizujemy zawartość. Coś jak:

$.ajax({
  url: '/myEndpoint.json',
  success: function ( data, status ) {
    $('ul#log').append('<li>Data Received!</li>');
  }
});

W przypadku widoku wyglądającego tak:

<ul class="messages" id="log">
</ul>

Oprócz mieszania obaw mamy również te same problemy ze znaczeniem zamiaru, o których wspomniałem wcześniej. Co ważniejsze, musieliśmy ręcznie odwoływać się i aktualizować węzeł DOM. A jeśli chcemy usunąć wpis dziennika, musimy również w tym celu zakodować DOM. Jak testujemy logikę oprócz DOM? A jeśli chcemy zmienić prezentację?

To trochę niechlujny i delikatny wątły. Ale w AngularJS możemy to zrobić:

$http( '/myEndpoint.json' ).then( function ( response ) {
    $scope.log.push( { msg: 'Data Received!' } );
});

Nasz widok może wyglądać następująco:

<ul class="messages">
    <li ng-repeat="entry in log">{{ entry.msg }}</li>
</ul>

Ale jeśli o to chodzi, nasz pogląd może wyglądać następująco:

<div class="messages">
    <div class="alert" ng-repeat="entry in log">
        {{ entry.msg }}
    </div>
</div>

A teraz zamiast korzystać z nieuporządkowanej listy, używamy okien alarmowych Bootstrap. I nigdy nie musieliśmy zmieniać kodu kontrolera! Ale co ważniejsze, bez względu na to, gdzie i jak dziennik zostanie zaktualizowany, widok również się zmieni. Automatycznie. Schludny!

Chociaż nie pokazałem tego tutaj, powiązanie danych jest dwukierunkowe. Więc te komunikaty dziennika może być również edytować w widoku tylko w ten sposób: <input ng-model="entry.msg" />. I było wiele radości.

Wyraźna warstwa modelu

W jQuery DOM jest trochę podobny do modelu. Ale w AngularJS mamy oddzielną warstwę modelu, którą możemy zarządzać w dowolny sposób, całkowicie niezależnie od widoku. Pomaga to w powiązaniu powyższych danych, utrzymuje separację obaw i wprowadza znacznie większą testowalność. Inne odpowiedzi wspomniały o tym punkcie, więc zostawię to w tym miejscu.

Rozdzielenie obaw

Wszystkie powyższe elementy wiążą się z tym nadrzędnym tematem: oddziel swoje obawy. Twój pogląd jest oficjalnym zapisem tego, co ma się wydarzyć (w przeważającej części); twój model reprezentuje twoje dane; masz warstwę usługową do wykonywania zadań wielokrotnego użytku; robisz manipulację DOM i poszerzasz swój widok o dyrektywy; i sklejasz to wszystko razem ze sterownikami. Zostało to również wspomniane w innych odpowiedziach i jedyne, co chciałbym dodać, dotyczy testowalności, którą omawiam w innej sekcji poniżej.

Zastrzyk zależności

Pomaganie nam w rozwiązywaniu problemów to wstrzykiwanie zależności (DI). Jeśli pochodzisz z języka serwera (od Java do PHP ), prawdopodobnie znasz już tę koncepcję, ale jeśli jesteś facetem po stronie klienta pochodzącym z jQuery, ta koncepcja może wydawać się czymś głupim, zbędnym lub hipsterskim . Ale nie jest. :-)

Z szerokiej perspektywy, DI oznacza, że ​​możesz deklarować komponenty bardzo swobodnie, a następnie z dowolnego innego komponentu, po prostu poproś o jego instancję, a zostanie to przyznane. Nie musisz wiedzieć o ładowaniu zamówienia, lokalizacjach plików itp. Moc może nie być natychmiast widoczna, ale podam tylko jeden (powszechny) przykład: testowanie.

Powiedzmy, że w naszej aplikacji potrzebujemy usługi, która implementuje pamięć po stronie serwera za pośrednictwem interfejsu API REST oraz, w zależności od stanu aplikacji, również pamięć lokalną. Podczas przeprowadzania testów na naszych kontrolerach nie chcemy komunikować się z serwerem - w końcu testujemy kontroler . Możemy po prostu dodać próbną usługę o tej samej nazwie co nasz oryginalny komponent, a wtryskiwacz zapewni, że nasz kontroler automatycznie otrzyma fałszywy - nasz kontroler nie zna i nie musi znać różnicy.

Mówiąc o testowaniu ...

4. Rozwój oparty na testach - zawsze

To jest naprawdę część sekcji 3 poświęconej architekturze, ale jest to tak ważne, że umieszczam ją jako własną sekcję najwyższego poziomu.

Spośród wszystkich wtyczek jQuery, które widziałeś, używasz lub napisałeś, ile z nich miało towarzyszący zestaw testów? Niezbyt wielu, ponieważ jQuery nie jest do tego bardzo podatna. Ale AngularJS jest.

W jQuery jedynym sposobem na przetestowanie jest często utworzenie komponentu niezależnie za pomocą strony próbnej / demonstracyjnej, na której nasze testy mogą przeprowadzać manipulację DOM. Zatem musimy opracować komponent osobno, a następnie zintegrować go z naszą aplikacją. Jak niewygodne! Przez większość czasu, pracując z jQuery, wybieramy iterację zamiast programowania opartego na testach. A kto może nas winić?

Ale ponieważ mamy rozdzielone obawy, możemy iteracyjnie tworzyć testy oparte na testach w AngularJS! Załóżmy na przykład, że chcemy, aby super-prosta dyrektywa wskazywała w naszym menu, jaka jest nasza aktualna trasa. Możemy zadeklarować, co chcemy w świetle naszej aplikacji:

<a href="/hello" when-active>Hello</a>

Okej, teraz możemy napisać test na nieistniejącą when-activedyrektywę:

it( 'should add "active" when the route changes', inject(function() {
    var elm = $compile( '<a href="https://stackoverflow.com/hello" when-active>Hello</a>' )( $scope );

    $location.path('/not-matching');
    expect( elm.hasClass('active') ).toBeFalsey();

    $location.path( '/hello' );
    expect( elm.hasClass('active') ).toBeTruthy();
}));

A kiedy uruchomimy nasz test, możemy potwierdzić, że się nie powiedzie. Dopiero teraz powinniśmy stworzyć naszą dyrektywę:

.directive( 'whenActive', function ( $location ) {
    return {
        scope: true,
        link: function ( scope, element, attrs ) {
            scope.$on( '$routeChangeSuccess', function () {
                if ( $location.path() == element.attr( 'href' ) ) {
                    element.addClass( 'active' );
                }
                else {
                    element.removeClass( 'active' );
                }
            });
        }
    };
});

Nasz test jest teraz pozytywny i nasze menu działa zgodnie z żądaniem. Nasz rozwój jest zarówno iteracyjny, jak i oparty na testach. Wicked-cool.

5. Pod względem koncepcyjnym dyrektywy nie są pakowane w jQuery

Często słyszysz „manipuluj DOM tylko w dyrektywie”. To jest konieczność. Traktuj to z należytym szacunkiem!

Ale zanurzmy się trochę głębiej ...

Niektóre dyrektywy po prostu dekorują to, co już jest widoczne (pomyśl ngClass) i dlatego czasami wykonują manipulacje DOM od razu, a następnie są w zasadzie wykonywane. Ale jeśli dyrektywa jest jak „widget” i ma szablon, powinna również uwzględniać rozdzielenie obaw. Oznacza to, że szablon również powinien pozostać w dużej mierze niezależny od jego implementacji w funkcjach łącza i kontrolera.

AngularJS jest wyposażony w cały zestaw narzędzi, które sprawiają, że jest to bardzo łatwe; za pomocą ngClassmożemy dynamicznie aktualizować klasę; ngModelumożliwia dwukierunkowe wiązanie danych; ngShowi ngHideprogramowo pokaż lub ukryj element; i wiele innych - w tym tych, które sami piszemy. Innymi słowy, możemy zrobić wiele niesamowitości bez manipulacji DOM. Im mniej manipulacji DOM, tym łatwiejsze są testy dyrektyw, im łatwiej jest nadać im styl, tym łatwiej je zmienić w przyszłości, i tym bardziej są one zdatne do ponownego wykorzystania i dystrybucji.

Widzę wielu programistów, którzy dopiero zaczynają pracę w AngularJS, używając dyrektyw jako miejsca do rzucenia paczki jQuery. Innymi słowy, myślą: „skoro nie mogę manipulować DOM w kontrolerze, wezmę ten kod do dyrektywy”. Chociaż z pewnością jest to znacznie lepsze, często wciąż jest złe .

Pomyśl o loggerze, który zaprogramowaliśmy w sekcji 3. Nawet jeśli umieścimy to w dyrektywie, nadal chcemy to zrobić „Angular Way”. To wciąż nie ponosi żadnej manipulacji DOM! Wiele razy konieczna jest manipulacja DOM, ale jest to o wiele rzadsze niż myślisz! Przed przystąpieniem do manipulacji DOM gdziekolwiek w aplikacji, zadaj sobie pytanie, czy naprawdę potrzebujesz. Może być lepszy sposób.

Oto szybki przykład, który pokazuje wzór, który najczęściej widzę. Chcemy przełączany przycisk. (Uwaga: ten przykład jest nieco spreparowany i pełen skosh, aby przedstawić bardziej skomplikowane przypadki, które są rozwiązywane dokładnie w ten sam sposób.)

.directive( 'myDirective', function () {
    return {
        template: '<a class="btn">Toggle me!</a>',
        link: function ( scope, element, attrs ) {
            var on = false;

            $(element).click( function () {
                on = !on;
                $(element).toggleClass('active', on);
            });
        }
    };
});

Jest w tym kilka rzeczy źle:

  1. Po pierwsze, jQuery nigdy nie było konieczne. Nie zrobiliśmy tutaj nic, co wymagałoby jQuery!
  2. Po drugie, nawet jeśli jQuery jest już na naszej stronie, nie ma powodu, aby go tutaj używać; możemy po prostu użyć, angular.elementa nasz komponent będzie nadal działał po upuszczeniu do projektu, który nie ma jQuery.
  3. Po trzecie, nawet zakładając, że jQuery było wymagane do działania tej dyrektywy, jqLite ( angular.element) zawsze użyje jQuery, jeśli zostanie załadowana! Więc nie musimy używać $- możemy po prostu użyć angular.element.
  4. Po czwarte, ściśle związane z trzecim, jest to, że elementy jqLite nie muszą być zawijane $- elementprzekazane do linkfunkcji byłyby już elementem jQuery!
  5. Po piąte, o którym wspominaliśmy w poprzednich sekcjach, dlaczego mieszamy szablony z naszą logiką?

Tę dyrektywę można przepisać (nawet w bardzo skomplikowanych przypadkach!) O wiele prościej:

.directive( 'myDirective', function () {
    return {
        scope: true,
        template: '<a class="btn" ng-class="{active: on}" ng-click="toggle()">Toggle me!</a>',
        link: function ( scope, element, attrs ) {
            scope.on = false;

            scope.toggle = function () {
                scope.on = !scope.on;
            };
        }
    };
});

Ponownie, szablon zawiera się w szablonie, więc możesz (lub twoi użytkownicy) łatwo zamienić go na taki, który odpowiada dowolnemu stylowi, a logiki nigdy nie trzeba było dotykać. Wielokrotnego użytku - boom!

I są jeszcze wszystkie inne korzyści, takie jak testowanie - to proste! Niezależnie od tego, co znajduje się w szablonie, wewnętrzny interfejs API dyrektywy nigdy nie zostanie zmieniony, więc refaktoryzacja jest łatwa. Możesz zmienić szablon tak, jak chcesz, bez dotykania dyrektywy. I bez względu na to, co zmienisz, twoje testy wciąż przechodzą.

w00t!

Więc jeśli dyrektywy nie są tylko zbiorami funkcji podobnych do jQuery, to czym one są? Dyrektywy są w rzeczywistości rozszerzeniami HTML . Jeśli HTML nie robi czegoś, co trzeba, napisz dyrektywę, aby zrobić to za Ciebie, a następnie użyj go tak, jakby był częścią HTML.

Innymi słowy, jeśli angularjs nie robi coś po wyjęciu z pudełka, myśleć, jak zespół będzie realizować go zmieścić w prawo z ngClick, ngClasset al.

Podsumowanie

Nawet nie używaj jQuery. Nawet tego nie uwzględniaj. To cię powstrzyma. A kiedy dojdziesz do problemu, który Twoim zdaniem wiesz, jak rozwiązać już w jQuery, zanim sięgniesz po niego $, spróbuj pomyśleć o tym, jak to zrobić w ramach AngularJS. Jeśli nie wiesz, zapytaj! 19 razy na 20, najlepszym sposobem na to nie jest jQuery, a próba rozwiązania problemu za pomocą jQuery daje więcej pracy dla Ciebie.

Josh David Miller
źródło
204
Myślę, że włączenie pracy z JQuery w aplikacji kątowej jest ważnym przypadkiem użycia ze względu na wszystkie istniejące wtyczki JQuery, które zostały napisane. Nie przepisuję FancyBox w jQuery, aby zachować czystą aplikację Angular.
taudep
119
@taudep Nie sądzę, abyśmy się nie zgadzali tak bardzo, jak myślisz. Większość wtyczek jQuery można tanio przepisać w AngularJS iw takich przypadkach powinniśmy to zrobić. Jeśli szukasz czegoś złożonego, dla którego nie ma odpowiednika, wybierz to. Cytat z części 2: „Najważniejsze jest to: podczas rozwiązywania najpierw„ pomyśl w AngularJS ”; jeśli nie możesz znaleźć rozwiązania, zapytaj społeczność; jeśli po tym wszystkim nie ma łatwego rozwiązania, możesz sięgnąć po jQuery . Ale nie pozwól, aby jQuery stało się kulą, bo nigdy nie opanujesz AngularJS. [wyróżnienie dodane]
Josh David Miller
67
chiński tłumaczy na tę wspaniałą odpowiedź, mam nadzieję, że będzie pomocny. hanzheng.github.io/tech/angularjs/2013/10/28/...
Han Zheng
18
@Benno Co rozumie przez „brak manipulacji DOM”, to że kod w dyrektywie nie wykonuje bezpośrednio manipulacji DOM. Ten kod nic nie wie o DOM, po prostu modyfikuje zmienne js w twoim modelu. Tak, efektem końcowym jest modyfikacja DOM, ale to dlatego, że poza kodem, który piszemy, istnieją powiązania, które reagują na zmiany naszych zmiennych, ale wewnątrz dyrektywy nic o tym nie wiemy, czyniąc czysty rozdział między manipulacją DOM a logika biznesowa. W przykładzie jQuery bezpośrednio zmieniasz DOM, mówiąc „dołącz ten tekst do tego elementu”
wired_in
11
@trusktr Jeśli deweloper kiedykolwiek ustawia wartość elementu wejściowego za pomocą jQuery w aplikacji AngularJS, popełnia poważny błąd. Jedynym wyjątkiem, o którym myślę, jest istniejąca wtyczka jQuery, która jest zbyt trudna do przeniesienia, która automatycznie zmienia dane wejściowe, w którym to przypadku podłączenie się do wywołania zwrotnego lub ustawienie zegarka jest absolutnie niezbędne, aby dostosować zmiany do aplikacji.
Josh David Miller
407

Tryb rozkazujący → deklaratywny

W jQuery selektory służą do znajdowania elementów DOM , a następnie do nich przypisywania / rejestrowania programów obsługi zdarzeń. Gdy zdarzenie zostanie wyzwolone, ten (imperatywny) kod zostanie wykonany w celu aktualizacji / zmiany DOM.

W AngularJS chcesz myśleć o widokach, a nie o elementach DOM. Widoki to (deklaratywny) HTML, który zawiera dyrektywy AngularJS . Dyrektywy konfigurują dla nas procedury obsługi zdarzeń i zapewniają nam dynamiczne wiązanie danych. Selektory są rzadko używane, więc potrzeba identyfikatorów (i niektórych typów klas) jest znacznie zmniejszona. Widoki są powiązane z modelami (za pomocą zakresów). Widoki są rzutem modelu. Zdarzenia zmieniają modele (tj. Dane, właściwości zakresu), a widoki prognozujące te modele są aktualizowane „automatycznie”.

W AngularJS pomyśl o modelach, a nie o elementach DOM wybranych przez jQuery, które przechowują twoje dane. Pomyśl o widokach jako rzutach tych modeli, a nie o rejestrowaniu wywołań zwrotnych w celu manipulowania tym, co widzi użytkownik.

Rozdzielenie obaw

jQuery stosuje dyskretny JavaScript - zachowanie (JavaScript) jest oddzielone od struktury (HTML).

AngularJS używa kontrolerów i dyrektyw (z których każda może mieć własny kontroler i / lub funkcje kompilacji i łączenia) w celu usunięcia zachowania z widoku / struktury (HTML). Angular ma również usługi i filtry, które pomagają oddzielić / uporządkować aplikację.

Zobacz także https://stackoverflow.com/a/14346528/215945

Projektowanie aplikacji

Jedno podejście do projektowania aplikacji AngularJS:

  1. Pomyśl o swoich modelach. Twórz usługi lub własne obiekty JavaScript dla tych modeli.
  2. Pomyśl o tym, jak chcesz zaprezentować swoje modele - swoje poglądy. Utwórz szablony HTML dla każdego widoku, używając niezbędnych dyrektyw, aby uzyskać dynamiczne wiązanie danych.
  3. Dołącz kontroler do każdego widoku (używając ng-view i routingu lub ng-kontrolera). Poproś kontrolera o znalezienie / uzyskanie tylko tych danych modelu, których widok potrzebuje do wykonania swojej pracy. Spraw, aby kontrolery były tak cienkie, jak to możliwe.

Dziedziczenie prototypowe

Z jQuery możesz wiele zrobić, nie wiedząc, jak działa dziedziczenie prototypowe JavaScript. Tworząc aplikacje AngularJS, unikniesz typowych problemów, jeśli dobrze rozumiesz dziedziczenie JavaScript. Zalecane lektury: Jakie są niuanse dziedziczenia prototypowego / prototypowego w AngularJS?

Mark Rajcok
źródło
1
czy możesz proszę wyjaśnić, w jaki sposób element dom różni się od widoku?
Rajkamal Subramanian
22
@rajkamal, element DOM jest (oczywiście) pojedynczym elementem, aw jQuery często wybieramy / celujemy / manipulujemy. Widok kątowy jest zbiorem / szablonem powiązanych elementów DOM: widok menu, widok nagłówka, widok stopki, widok na prawym pasku bocznym, widok profilu, może wiele widoków głównej zawartości (przełączanych za pomocą widoku ng). Zasadniczo chcesz podzielić swoje strony na różne widoki. Każdy widok ma własny powiązany kontroler. Każdy widok wyświetla część twojego modelu (modeli).
Mark Rajcok
3
jQuery NIE jest konieczne. oni whensą funkcjami wyższego rzędu, działającymi na elementach obiektu kolekcji jQuery.
Jack Viers
18
Więc jakiego rodzaju kod jest wykonywany w wywołaniu zwrotnym on? Tryb rozkazujący.
cwharris,
5
Ten imperatyw kontra deklaratywny jest tak naprawdę tylko kwestią abstrakcji. Ostatecznie cały kod deklaratywny (co zrobić) jest wdrażany imperatywnie (jak to zrobić) albo przez programistę w podprogramie na niższym poziomie abstrakcji, przez framework lub kompilator / interpreter. Stwierdzenie, że „jQuery jest bezwzględnie konieczne” jest dość dziwnym stwierdzeniem, szczególnie biorąc pod uwagę, że faktycznie zapewnia znacznie bardziej deklaratywne API w odniesieniu do „ręcznej” manipulacji DOM.
Alex
184

AngularJS vs. jQuery

AngularJS i jQuery przyjmują bardzo różne ideologie. Jeśli pochodzisz z jQuery, niektóre różnice mogą cię zaskoczyć. Angular może cię zdenerwować.

To normalne, powinieneś przepchnąć się. Kątowe jest tego warte.

Duża różnica (TLDR)

jQuery daje zestaw narzędzi do wybierania dowolnych bitów DOM i wprowadzania do nich zmian ad-hoc. Kawałek po kawałku możesz zrobić praktycznie wszystko.

Zamiast tego AngularJS daje ci kompilator .

Oznacza to, że AngularJS odczytuje cały DOM od góry do dołu i traktuje go jako kod, dosłownie jako instrukcje dla kompilatora. Przechodząc przez DOM, szuka określonych dyrektyw ( dyrektyw kompilatora), które mówią kompilatorowi AngularJS, jak się zachować i co robić. Dyrektywy to małe obiekty pełne JavaScript, które można dopasować do atrybutów, tagów, klas, a nawet komentarzy.

Gdy kompilator Angular stwierdzi, że element DOM pasuje do określonej dyrektywy, wywołuje funkcję dyrektywy, przekazując jej element DOM, dowolne atrybuty, bieżący zakres $ (który jest lokalnym magazynem zmiennych) i kilka innych przydatnych bitów. Te atrybuty mogą zawierać wyrażenia, które mogą być interpretowane przez dyrektywę i które mówią jej, jak renderować i kiedy należy się przerysować.

Dyrektywy mogą z kolei pobierać dodatkowe komponenty Angular, takie jak kontrolery, usługi itp. To, co wychodzi na dół kompilatora, to w pełni ukształtowana aplikacja internetowa, podłączona i gotowa do pracy.

Oznacza to, że Angular jest oparty na szablonie . Twój szablon obsługuje JavaScript, a nie na odwrót. Jest to radykalne odwrócenie ról i całkowite przeciwieństwo dyskretnego JavaScript, który piszemy od około 10 lat. To może trochę przyzwyczaić się.

Jeśli brzmi to jak zbyt nakazowe i ograniczające, nic nie może być dalsze od prawdy. Ponieważ AngularJS traktuje kod HTML jako kod, w aplikacji sieciowej występuje ziarnistość na poziomie HTML . Wszystko jest możliwe, a większość rzeczy jest zaskakująco łatwa po wykonaniu kilku skoków koncepcyjnych.

Zejdźmy do sedna.

Po pierwsze, Angular nie zastępuje jQuery

Angular i jQuery robią różne rzeczy. AngularJS zapewnia zestaw narzędzi do tworzenia aplikacji internetowych. jQuery daje głównie narzędzia do modyfikowania DOM. Jeśli jQuery jest obecny na twojej stronie, AngularJS użyje go automatycznie. Jeśli tak nie jest, AngularJS jest dostarczany z jQuery Lite, która jest odciętą, ale wciąż doskonale użyteczną wersją jQuery.

Misko lubi jQuery i nie sprzeciwia się używaniu go. Jednak w miarę postępów przekonasz się, że możesz wykonać prawie całą swoją pracę za pomocą kombinacji zakresu, szablonów i dyrektyw, i powinieneś preferować ten przepływ pracy tam, gdzie to możliwe, ponieważ twój kod będzie bardziej dyskretny, konfigurowalny i więcej Kątowy.

Jeśli używasz jQuery, nie powinieneś posypywać go wszędzie. Prawidłowe miejsce do manipulacji DOM w AngularJS znajduje się w dyrektywie. Więcej na ten temat później.

Dyskretny JavaScript z Selektorami vs. Deklaratywne szablony

jQuery jest zwykle stosowany dyskretnie. Twój kod JavaScript jest umieszczony w nagłówku (lub stopce) i jest to jedyne miejsce, o którym wspomniano. Używamy selektorów do wybierania fragmentów strony i pisania wtyczek w celu modyfikacji tych części.

JavaScript jest pod kontrolą. HTML ma całkowicie niezależne istnienie. Twój HTML pozostaje semantyczny nawet bez JavaScript. Atrybuty Onclick są bardzo złą praktyką.

Jedną z pierwszych rzeczy, które zauważysz w AngularJS, jest to, że niestandardowe atrybuty są wszędzie . Twój HTML będzie zaśmiecony atrybutami ng, które są zasadniczo atrybutami onClick na sterydach. Są to dyrektywy (dyrektywy kompilatora) i są jednym z głównych sposobów zaczepienia szablonu do modelu.

Kiedy po raz pierwszy to zobaczysz, możesz ulec pokusie, aby napisać AngularJS jako staroświecki JavaScript uciążliwy (tak jak na początku). W rzeczywistości AngularJS nie przestrzega tych zasad. W AngularJS Twój HTML5 jest szablonem. Jest on kompilowany przez AngularJS w celu stworzenia twojej strony internetowej.

To pierwsza duża różnica. Aby jQuery, twoja strona internetowa była DOM, którym można manipulować. Dla AngularJS twój HTML to kod do skompilowania. AngularJS odczytuje całą stronę internetową i dosłownie kompiluje ją w nową stronę internetową za pomocą wbudowanego kompilatora.

Twój szablon powinien być deklaratywny; jego znaczenie powinno być jasne, po prostu je czytając. Używamy niestandardowych atrybutów o znaczących nazwach. Tworzymy nowe elementy HTML, znowu o znaczących nazwach. Projektant z minimalną znajomością HTML i bez umiejętności kodowania może odczytać szablon AngularJS i zrozumieć, co robi. On lub ona może dokonywać modyfikacji. To jest sposób kątowy.

Szablon znajduje się na siedzeniu kierowcy.

Jednym z pierwszych pytań, które zadałem sobie podczas uruchamiania AngularJS i przeglądania samouczków, jest: „Gdzie jest mój kod?” . Nie napisałem JavaScript, a mimo to mam takie zachowanie. Odpowiedź jest oczywista. Ponieważ AngularJS kompiluje DOM, AngularJS traktuje Twój HTML jako kod. W wielu prostych przypadkach często wystarczy po prostu napisać szablon i pozwolić AngularJS skompilować go dla aplikacji.

Twój szablon napędza twoją aplikację. Jest traktowany jak DSL . Piszesz komponenty AngularJS, a AngularJS zajmie się ich wciągnięciem i udostępnieniem we właściwym czasie w oparciu o strukturę twojego szablonu. To bardzo różni się od standardowego wzorca MVC , w którym szablon jest tylko do wydruku.

Na przykład jest bardziej podobny do XSLT niż Ruby on Rails .

Jest to radykalna inwersja kontroli, do której trzeba się przyzwyczaić.

Przestań próbować prowadzić aplikację z JavaScript. Niech szablon steruje aplikacją, a AngularJS zajmie się połączeniem komponentów. To także jest sposób kątowy.

Semantyczny HTML a modele semantyczne

Dzięki jQuery strona HTML powinna zawierać znaczącą treść semantyczną. Jeśli JavaScript jest wyłączony (przez użytkownika lub wyszukiwarkę), twoje treści pozostaną dostępne.

Ponieważ AngularJS traktuje Twoją stronę HTML jako szablon. Szablon nie powinien być semantyczny, ponieważ treść jest zazwyczaj przechowywana w modelu, który ostatecznie pochodzi z interfejsu API. AngularJS kompiluje Twój DOM z modelem, aby utworzyć semantyczną stronę internetową.

Twoje źródło HTML nie jest już semantyczne, zamiast tego interfejs API i skompilowany DOM są semantyczne.

W AngularJS, co oznacza, że ​​żyje w modelu, HTML jest tylko szablonem, tylko do wyświetlania.

W tym momencie prawdopodobnie masz wiele pytań dotyczących SEO i dostępności, i słusznie. Tutaj są otwarte problemy. Większość czytników ekranu będzie teraz analizować JavaScript. Wyszukiwarki mogą również indeksować treści AJAXed . Niemniej jednak upewnij się, że używasz adresów URL typu pushstate i masz przyzwoitą mapę witryny. Tutaj znajduje się omówienie problemu: https://stackoverflow.com/a/23245379/687677

Rozdzielenie obaw (SOC) vs. MVC

Separacja problemów (SOC) to wzorzec, który wyrósł w ciągu wielu lat tworzenia stron internetowych z różnych powodów, w tym SEO, dostępności i niezgodności przeglądarki. To wygląda tak:

  1. HTML - znaczenie semantyczne. HTML powinien być samodzielny.
  2. CSS - Stylizacja, bez CSS strona jest nadal czytelna.
  3. JavaScript - zachowanie, bez skryptu zawartość pozostaje.

Ponownie, AngularJS nie gra według swoich zasad. W jednym uderzeniu AngularJS usuwa dekadę otrzymanej mądrości i zamiast tego implementuje wzór MVC, w którym szablon nie jest już semantyczny, ani trochę.

To wygląda tak:

  1. Model - twoje modele zawierają dane semantyczne. Modele są zwykle obiektami JSON . Modele istnieją jako atrybuty obiektu o nazwie $ scope. Możesz także przechowywać przydatne funkcje narzędziowe w $ scope, do których szablony mają dostęp.
  2. Widok - Twoje widoki są napisane w HTML. Widok zwykle nie jest semantyczny, ponieważ dane znajdują się w modelu.
  3. Kontroler - Twój kontroler to funkcja JavaScript, która przechwytuje widok do modelu. Jego funkcją jest inicjalizacja $ scope. W zależności od aplikacji może być konieczne utworzenie kontrolera. Na stronie możesz mieć wiele kontrolerów.

MVC i SOC nie znajdują się na przeciwległych końcach tej samej skali, lecz na zupełnie innych osiach. SOC nie ma sensu w kontekście AngularJS. Musisz o tym zapomnieć i iść dalej.

Jeśli, podobnie jak ja, przeżyłeś wojny przeglądarkowe, możesz uznać ten pomysł za obraźliwy. Poradzić sobie, to będzie tego warte, obiecuję.

Wtyczki a dyrektywy

Wtyczki rozszerzają jQuery. Dyrektywy AngularJS rozszerzają możliwości twojej przeglądarki.

W jQuery definiujemy wtyczki, dodając funkcje do jQuery.prototype. Następnie podłączamy je do DOM, wybierając elementy i wywołując wtyczkę na wyniku. Chodzi o rozszerzenie możliwości jQuery.

Na przykład, jeśli chcesz mieć karuzelę na swojej stronie, możesz zdefiniować nieuporządkowaną listę cyfr, być może owiniętą w element nawigacyjny. Możesz następnie napisać jQuery, aby wybrać listę na stronie i zmienić jej styl jako galerię z limitami czasu na animację przesuwaną.

W AngularJS definiujemy dyrektywy. Dyrektywa jest funkcją, która zwraca obiekt JSON. Ten obiekt informuje AngularJS, jakich elementów DOM należy szukać i jakie zmiany w nich wprowadzić. Dyrektywy są podłączone do szablonu za pomocą atrybutów lub elementów, które wymyśliłeś. Chodzi o rozszerzenie możliwości HTML o nowe atrybuty i elementy.

AngularJS polega na rozszerzeniu możliwości natywnego wyglądu HTML. Powinieneś pisać HTML, który wygląda jak HTML, rozszerzony o niestandardowe atrybuty i elementy.

Jeśli chcesz karuzeli, po prostu użyj <carousel />elementu, a następnie zdefiniuj dyrektywę, aby pobrać szablon i sprawić, by ten frajer działał.

Wiele małych dyrektyw vs. duże wtyczki z przełącznikami konfiguracji

JQuery ma tendencję do pisania świetnych dużych wtyczek, takich jak lightbox, które następnie konfigurujemy, przekazując liczne wartości i opcje.

To błąd w AngularJS.

Weź przykład listy rozwijanej. Pisząc rozwijaną wtyczkę, możesz ulec pokusie kodowania w modułach obsługi kliknięć, być może funkcji dodania szewronu, który jest w górę lub w dół, być może zmień klasę rozwiniętego elementu, pokaż ukryj menu, wszystkie przydatne rzeczy.

Aż chcesz wprowadzić małą zmianę.

Załóżmy, że masz menu, które chcesz rozwinąć po najechaniu myszą. Cóż, teraz mamy problem. Nasza wtyczka ma dla nas funkcję obsługi kliknięć. Będziemy musieli dodać opcję konfiguracji, aby działała inaczej w tym konkretnym przypadku.

W AngularJS piszemy mniejsze dyrektywy. Nasza dyrektywa w sprawie rozwijania byłaby absurdalnie mała. Może utrzymywać stan złożony i zapewniać metody fold (), rozkładanie () lub przełączanie (). Te metody po prostu zaktualizują $ scope.menu.visible, który jest wartością logiczną utrzymującą stan.

Teraz w naszym szablonie możemy to połączyć:

<a ng-click="toggle()">Menu</a>
<ul ng-show="menu.visible">
  ...
</ul>

Potrzebujesz aktualizacji po najechaniu kursorem myszy?

<a ng-mouseenter="unfold()" ng-mouseleave="fold()">Menu</a>
<ul ng-show="menu.visible">
  ...
</ul>

Szablon napędza aplikację, dzięki czemu uzyskujemy szczegółowość na poziomie HTML. Jeśli chcemy wprowadzić wyjątki dla poszczególnych przypadków, szablon ułatwia to.

Zamknięcie a zakres $

Wtyczki JQuery są tworzone w zamknięciu. Prywatność jest utrzymywana w ramach tego zamknięcia. Od Ciebie zależy utrzymanie łańcucha zasięgu w ramach tego zamknięcia. Naprawdę masz dostęp tylko do zestawu węzłów DOM przekazanych do wtyczki przez jQuery, a także do wszystkich zmiennych lokalnych zdefiniowanych w zamknięciu i wszelkich zdefiniowanych przez Ciebie globałów. Oznacza to, że wtyczki są całkowicie samodzielne. To dobrze, ale może stać się restrykcyjne podczas tworzenia całej aplikacji. Próba przekazywania danych między sekcjami strony dynamicznej staje się obowiązkiem.

AngularJS ma obiekty $ scope. Są to specjalne obiekty tworzone i obsługiwane przez AngularJS, w których przechowujesz swój model. Niektóre dyrektywy odradzają nowy zakres $, który domyślnie dziedziczy po zawinięciu zakresu $ przy użyciu prototypowego dziedziczenia JavaScript. Obiekt $ scope jest dostępny w kontrolerze i widoku.

To sprytna część. Ponieważ struktura dziedziczenia zakresu $ z grubsza odpowiada strukturze DOM, elementy mają dostęp do własnego zakresu, a wszelkie zawierające go zakresy płynnie, aż do globalnego zakresu $ (który nie jest taki sam jak zasięg globalny).

To znacznie ułatwia przekazywanie danych i przechowywanie danych na odpowiednim poziomie. Jeśli rozwijane jest rozwijane menu, tylko zakres rozwijany $ musi o tym wiedzieć. Jeśli użytkownik zaktualizuje swoje preferencje, możesz zaktualizować globalny zasięg $, a wszelkie zagnieżdżone zakresy nasłuchujące preferencji użytkownika zostaną automatycznie powiadomione.

Może się to wydawać skomplikowane, w rzeczywistości, kiedy się w niego zrelaksujesz, to jak latanie. Nie musisz tworzyć obiektu $ scope, AngularJS tworzy go i konfiguruje dla Ciebie, poprawnie i odpowiednio w oparciu o twoją hierarchię szablonów. Następnie AngularJS udostępnia go komponentowi za pomocą magii wstrzykiwania zależności (więcej na ten temat później).

Ręczne zmiany DOM a wiązanie danych

W jQuery ręcznie wprowadzasz wszystkie zmiany DOM. Konstruujesz nowe elementy DOM programowo. Jeśli masz tablicę JSON i chcesz umieścić ją w DOM, musisz napisać funkcję do wygenerowania HTML i wstawienia go.

W AngularJS możesz to również zrobić, ale zachęca się do korzystania z wiązania danych. Zmień model, a ponieważ DOM jest z nim powiązany za pomocą szablonu, DOM automatycznie się zaktualizuje, nie wymaga interwencji.

Ponieważ wiązanie danych odbywa się z szablonu, przy użyciu atrybutu lub składni nawiasów klamrowych, jest to bardzo łatwe. Jest z tym związany niewielki narzut kognitywny, więc cały czas to robisz.

<input ng-model="user.name" />

Wiąże element wejściowy z $scope.user.name. Aktualizacja danych wejściowych spowoduje zaktualizowanie wartości w bieżącym zakresie i odwrotnie.

Również:

<p>
  {{user.name}}
</p>

wyświetli nazwę użytkownika w akapicie. Jest to aktywne wiązanie, więc jeśli $scope.user.namewartość zostanie zaktualizowana, szablon również się zaktualizuje.

Ajax cały czas

W jQuery wywołanie Ajax jest dość proste, ale wciąż możesz pomyśleć dwa razy. Jest dodatkowa złożoność do przemyślenia i spory kawałek skryptu do utrzymania.

W AngularJS Ajax jest Twoim domyślnym rozwiązaniem, które dzieje się przez cały czas, prawie bez zauważenia. Możesz dołączyć szablony z ng-include. Możesz zastosować szablon z najprostszą niestandardową dyrektywą. Możesz zawinąć wywołanie Ajax w usługę i stworzyć sobie usługę GitHub lub Flickr , do której możesz uzyskać dostęp z zadziwiającą łatwością.

Obiekty serwisowe a funkcje pomocnicze

W jQuery, jeśli chcemy wykonać małe zadanie niezwiązane z domem, takie jak pobieranie kanału z API, możemy napisać małą funkcję, aby to zrobić w naszym zamknięciu. To prawidłowe rozwiązanie, ale co, jeśli chcemy często uzyskiwać dostęp do tego kanału? Co jeśli chcemy ponownie użyć tego kodu w innej aplikacji?

AngularJS daje nam obiekty usługowe.

Usługi to proste obiekty zawierające funkcje i dane. Zawsze są singletonami, co oznacza, że ​​nigdy nie może być więcej niż jeden z nich. Powiedzmy, że chcemy uzyskać dostęp do interfejsu API przepełnienia stosu, możemy napisać StackOverflowServicemetodę definiującą metody.

Powiedzmy, że mamy wózek na zakupy. Możemy zdefiniować ShoppingCartService, który utrzymuje nasz koszyk i zawiera metody dodawania i usuwania przedmiotów. Ponieważ usługa jest singletonem i jest współdzielona przez wszystkie inne komponenty, każdy obiekt, który musi zapisać w koszyku i pobrać z niego dane. To zawsze ten sam wózek.

Obiekty usług są samodzielnymi komponentami AngularJS, które możemy wykorzystywać i wykorzystywać ponownie, gdy uznamy to za stosowne. Są to proste obiekty JSON zawierające funkcje i dane. Są one zawsze singletonami, więc jeśli przechowujesz dane w usłudze w jednym miejscu, możesz uzyskać te dane gdzie indziej, po prostu prosząc o tę samą usługę.

Iniekcja zależności (DI) vs. Instatiation - inaczej de-spaghettification

AngularJS zarządza twoimi zależnościami. Jeśli chcesz mieć obiekt, po prostu się do niego odszukaj, a AngularJS go dla ciebie dostanie.

Dopóki nie zaczniesz z tego korzystać, trudno jest wyjaśnić, jak wielki jest to dar czasu. W jQuery nie istnieje coś takiego jak AngularJS DI.

DI oznacza, że ​​zamiast pisać aplikację i łączyć ją razem, zamiast tego definiujesz bibliotekę komponentów, z których każda jest identyfikowana przez ciąg znaków.

Powiedzmy, że mam komponent o nazwie „FlickrService”, który definiuje metody pobierania kanałów JSON z Flickr. Teraz, jeśli chcę napisać kontroler, który może uzyskać dostęp do Flickr, muszę tylko odwołać się do „FlickrService” według nazwy, kiedy deklaruję kontroler. AngularJS zajmie się utworzeniem instancji komponentu i udostępnieniem go mojemu kontrolerowi.

Na przykład tutaj definiuję usługę:

myApp.service('FlickrService', function() {
  return {
    getFeed: function() { // do something here }
  }
});

Teraz, gdy chcę skorzystać z tej usługi, po prostu nazywam ją po imieniu w następujący sposób:

myApp.controller('myController', ['FlickrService', function(FlickrService) {
  FlickrService.getFeed()
}]);

AngularJS rozpozna, że ​​obiekt FlickrService jest potrzebny do utworzenia instancji kontrolera i dostarczy nam jeden.

To sprawia, że ​​łączenie elementów jest bardzo łatwe i prawie całkowicie eliminuje tendencję do spagetyfikacji. Mamy płaską listę komponentów, a AngularJS przekazuje je nam jeden po drugim, kiedy i kiedy ich potrzebujemy.

Modułowa architektura usług

jQuery mówi niewiele o tym, jak powinieneś zorganizować swój kod. AngularJS ma opinie.

AngularJS daje moduły, w których możesz umieścić swój kod. Jeśli piszesz na przykład skrypt, który komunikuje się z Flickr, możesz utworzyć moduł Flickr, w którym będą zawijać wszystkie funkcje związane z Flickr. Moduły mogą zawierać inne moduły (DI). Główną aplikacją jest zwykle moduł, który powinien obejmować wszystkie pozostałe moduły, od których będzie zależeć twoja aplikacja.

Otrzymasz proste ponowne użycie kodu, jeśli chcesz napisać kolejną aplikację opartą na Flickr, możesz po prostu dołączyć moduł Flickr i voila, masz dostęp do wszystkich funkcji związanych z Flickr w nowej aplikacji.

Moduły zawierają komponenty AngularJS. Gdy dołączymy moduł, wszystkie komponenty w tym module stają się dla nas dostępne jako prosta lista identyfikowana przez ich unikalne ciągi . Następnie możemy wstrzyknąć sobie te komponenty za pomocą mechanizmu wstrzykiwania zależności AngularJS.

Podsumowując

AngularJS i jQuery nie są wrogami. Można bardzo ładnie używać jQuery w AngularJS. Jeśli dobrze używasz AngularJS (szablony, wiązanie danych, zakres $, dyrektywy itp.), Zauważysz, że potrzebujesz dużo mniej jQuery, niż mogłoby być wymagane.

Najważniejsze do zrozumienia jest to, że Twój szablon napędza twoją aplikację. Przestań próbować pisać duże wtyczki, które robią wszystko. Zamiast tego napisz małe dyrektywy, które wykonują jedną rzecz, a następnie napisz prosty szablon, aby je połączyć.

Nie myśl o dyskretnym JavaScript, a zamiast tego myśl o rozszerzeniach HTML.

Moja mała książka

Tak bardzo podekscytowałem się AngularJS, że napisałem o nim krótką książkę, którą z przyjemnością przeczytacie online http://nicholasjohnson.com/angular-book/ . Mam nadzieję, że to jest pomocne.

superluminarny
źródło
6
Pomysł, że „Separation of Concerns” różni się od „MVC (Model, View, Controller)” jest całkowicie fałszywy. Model rozdzielania problemów w językach internetowych (HTML, CSS i JS) robi to, pozwalając ludziom umieszczać rzeczy na stronie internetowej (znaczniki / HTML) bez dbania o to, jak to wygląda (styl / układ / CSS) lub co robi (Zdarzenia DOM / AJAX / JavaScript). MVC rozdziela również obawy. Każda „warstwa” we wzorze MVC ma odrębną rolę - dane, routing / logika lub rendering. Warstwy są połączone wywołaniami zwrotnymi, trasami i powiązaniami modelu. Teoretycznie osoba może specjalizować się w każdej warstwie, co często ma miejsce.
Jako osoba wywodząca się ze ścisłego tła SOC i jako wieloletni zwolennik standardów internetowych sięgających czasów wojen przeglądarskich, początkowo uważałem, że nie semantyczne, nie walidujące szablony Angulara są kłopotliwe. Chciałem tylko wyjaśnić, że aby napisać Angular, należy puścić SOC, ponieważ jest to ogólnie praktykowane. To może być trudne przejście.
superluminarny
Masz rację. SOC jest szerokim pojęciem, ale w świecie internetowym SOC ma (lub prawdopodobnie miał) bardzo konkretne znaczenie: semantyczny HTML, prezentacja CSS i JavaScript dla zachowania. Robię pewne założenia dotyczące mojej publiczności, które być może nie są rozsądne, dlatego też powinienem przeprosić.
superluminarny
Uważam, że twoja odpowiedź jest najbardziej jasna i pouczająca. Jestem tu całkiem początkującym, więc jeśli mam rozszerzenie do zmiany istniejącej strony (której nie kontroluję), czy powinienem zachować JQuery?
Daniel Möller
152

Czy potrafisz opisać niezbędną zmianę paradygmatu?

Imperatyw vs Deklaratywny

Dzięki jQuery krok po kroku informujesz DOM, co musi się wydarzyć. Dzięki AngularJS opisujesz , jakie wyniki chcesz, ale nie wiesz, jak to zrobić. Więcej na ten temat tutaj . Zobacz także odpowiedź Marka Rajcoka.

Jak inaczej projektować i projektować aplikacje internetowe po stronie klienta?

AngularJS to cała platforma po stronie klienta, która wykorzystuje wzorzec MVC (sprawdź ich graficzną reprezentację ). Koncentruje się on w dużej mierze na oddzieleniu obaw.

Jaka jest największa różnica? Co powinienem przestać robić / używać; co powinienem zacząć robić / używać?

jQuery to biblioteka

AngularJS to piękny framework po stronie klienta, wysoce testowalny, który łączy w sobie mnóstwo fajnych rzeczy, takich jak MVC, wstrzykiwanie zależności , wiązanie danych i wiele innych.

Koncentruje się na rozdzieleniu problemów i testowaniu (testy jednostkowe i kompleksowe), co ułatwia rozwój oparty na testach.

Najlepszym sposobem na rozpoczęcie jest przejście przez niesamowity samouczek . Możesz przejść przez te kroki w ciągu kilku godzin; jednak w przypadku, gdy chcesz opanować koncepcje za kulisami, zawierają one niezliczoną ilość materiałów pomocniczych do dalszego czytania.

Czy są jakieś względy / ograniczenia po stronie serwera?

Możesz go użyć w istniejących aplikacjach, w których już używasz czystego jQuery. Jeśli jednak chcesz w pełni skorzystać z funkcji AngularJS, możesz rozważyć kodowanie po stronie serwera przy użyciu podejścia RESTful .

Dzięki temu możesz wykorzystać fabrykę zasobów , która tworzy abstrakcję interfejsu API RESTful po stronie serwera i sprawia, że ​​wywołania po stronie serwera (pobieranie, zapisywanie, usuwanie itp.) Są niezwykle łatwe.

Ulises
źródło
27
Myślę, że rozmazujesz wody, mówiąc o tym, jak jQuery jest „biblioteką”, a Angular jest „strukturą”… po pierwsze, myślę, że można argumentować, że jQuery jest strukturą… to abstrakcja manipulacji DOM i obsługi zdarzeń. Może to nie być ramy dla tego samego rodzaju, co Angular, ale to jest dylemat, w którym znajduje się pytający: tak naprawdę nie znają różnicy między Angular i jQuery, i dla wszystkich pytających wie, jQuery jest ramy do budowania stron internetowych obciążonych przez klientów. Dlatego kłótnia o terminologię nie wyjaśni sprawy.
Zando
15
Myślę, że jesteś tym, który się myli. To pytanie dotyczy dokładnie tego stackoverflow.com/questions/7062775 . Również ta odpowiedź może pomóc w wyjaśnieniu różnicy między frameworkiem a biblioteką: stackoverflow.com/a/148759/620448
Ulises
6
Biblioteka nie staje się „strukturą” tylko dlatego, że jej zbiór funkcji jest szczególnie użyteczny lub duży. Ramy podejmują decyzje za Ciebie. Kiedy zaczniesz używać AngularJS, prawdopodobnie będziesz z nim związany ze względu na jego naturę. (Np .: Powinieneś aktualizować DOM tylko w dyrektywach, w przeciwnym razie coś się zepsuje.) To dlatego, że AngularJS jest strukturą. Korzystając z jQuery, można stosunkowo łatwo mieszać i dopasowywać narzędzia przy minimalnym ryzyku konfliktu. Wynika to z faktu, że jQuery jest biblioteką, a przynajmniej pół przyzwoitą.
8
Biblioteka jest kod, który nazywasz. Ramy jest kod, który wywołuje kod. Według tej definicji Angular jest ramą. Dostarczasz mu komponenty, a Angular dba o to, aby Twoje komponenty były tworzone z zależnościami, których potrzebują.
superluminarny
84

Aby opisać „zmianę paradygmatu”, myślę, że krótka odpowiedź może wystarczyć.

AngularJS zmienia sposób wyszukiwania elementów

W jQuery zwykle używasz selektorów do znajdowania elementów, a następnie łączysz je:
$('#id .class').click(doStuff);

W AngularJS używasz dyrektyw, aby bezpośrednio oznaczyć elementy, aby je połączyć:
<a ng-click="doStuff()">

AngularJS nie potrzebuje (ani nie chce) znajdować elementów za pomocą selektorów - podstawowa różnica między jqLite AngularJS a pełnym jQuery polega na tym, że jqLite nie obsługuje selektorów .

Kiedy więc ludzie mówią: „nie dołączaj jQuery”, dzieje się tak głównie dlatego, że nie chcą, abyś używał selektorów; chcą, abyś nauczył się korzystać z dyrektyw zamiast tego. Bezpośredni, nie wybierz!

Scott Rippey
źródło
13
Podobnie jak zrzeczenie się, istnieje wiele większych różnic między Angular i jQuery. Ale znalezienie elementów wymaga zmiany sposobu myślenia.
Scott Rippey
1
wybacz mi, jeśli się mylę, ale myślałem, że do wybrania elementu DOM użyłeś selektora? Wolisz zachować każdą część nowo załadowanego interfejsu użytkownika, zamiast po prostu wybierać jeden lub dwa elementy, które użytkownik może kliknąć w locie za pomocą selektora? brzmi dla mnie trudniej ...
RozzA
3
@AlexanderPritchard W Angular chodzi o to, że nie wybierasz z JavaScript, tylko bezpośrednio z szablonu. To odwrócenie kontroli, które daje moc w ręce projektanta. Jest to celowa zasada projektowania. Aby naprawdę uzyskać Angular, musisz dokładnie przemyśleć swój kod. To trudna zmiana.
superluminarny
3
@superluminary What a great quote! „nie wybieraj; bezpośrednio!” Poważnie, wykorzystam to.
Scott Rippey
1
To jedna z moich ulubionych rzeczy w AngularJS. Nie muszę się martwić, że zespół UX zepsuje moją funkcjonalność lub że zepsuję ich style. Używają klas, ja używam dyrektyw, kropka. Ani trochę nie tęsknię za selektorami.
adam0101
69

jQuery

jQuery tworzy absurdalnie długie komendy JavaScript, takie jak getElementByHerpDerpkrótsze i dla różnych przeglądarek.

AngularJS

AngularJS pozwala tworzyć własne tagi / atrybuty HTML, które działają dobrze w przypadku dynamicznych aplikacji internetowych (ponieważ HTML został zaprojektowany dla stron statycznych).

Edytować:

Mówiąc „Mam doświadczenie w jQuery, jak myślę w AngularJS?” jest jak powiedzenie „Mam tło HTML, jak myślę w JavaScript?” Fakt, że zadajesz pytanie, pokazuje, że najprawdopodobniej nie rozumiesz podstawowych celów tych dwóch zasobów. Właśnie dlatego zdecydowałem się odpowiedzieć na to pytanie, po prostu wskazując zasadniczą różnicę, zamiast przeglądać listę, mówiąc: „AngularJS korzysta z dyrektyw, podczas gdy jQuery używa selektorów CSS do stworzenia obiektu jQuery, który robi to i tamto itp.…” . To pytanie nie wymaga długiej odpowiedzi.

jQuery to sposób na ułatwienie programowania JavaScript w przeglądarce. Krótsze polecenia w różnych przeglądarkach itp.

AngularJS rozszerza HTML, więc nie musisz rozrzucać się <div>po całym miejscu, aby stworzyć aplikację. Sprawia, że ​​HTML faktycznie działa dla aplikacji, a nie dla tego, do czego został zaprojektowany, czyli statycznych, edukacyjnych stron internetowych. Osiąga to w sposób okrężny przy użyciu JavaScript, ale zasadniczo jest to rozszerzenie HTML, a nie JavaScript.

Nick Manning
źródło
@Robert zależy od tego, co robisz. $(".myclass")jest niezwykle powszechny i ​​w jQuery jest o wiele łatwiejszy niż PO-JavaScript.
Rob Grant
61

jQuery: dużo myślisz o „PYTANIE O DOM ” dla elementów DOM i zrobieniu czegoś.

AngularJS: Model jest prawdą i zawsze myślisz z tego KĄTA.

Na przykład, gdy otrzymujesz dane z serwera THE, które zamierzasz wyświetlać w jakimś formacie w DOM, w jQuery, musisz '1. ZNAJDŹ, gdzie w DOM chcesz umieścić te dane, „2. UPDATE / APPEND 'go tam poprzez utworzenie nowego węzła lub po prostu ustawienie jego innerHTML . Następnie, gdy chcesz zaktualizować ten widok, wtedy „3. ZNAJDŹ lokalizację i „4. AKTUALIZACJA'. Ten cykl wyszukiwania i aktualizowania wszystkich czynności wykonywanych w tym samym kontekście pobierania i formatowania danych z serwera zniknął w AngularJS.

Dzięki AngularJS masz swój model (obiekty JavaScript, do których już jesteś przyzwyczajony), a wartość modelu mówi ci o modelu (oczywiście) i o widoku, a operacja na modelu automatycznie propaguje się do widoku, więc nie „ muszę o tym pomyśleć. Znajdziesz się w AngularJS i nie znajdziesz już rzeczy w DOM.

Innymi słowy, w jQuery musisz pomyśleć o selektorach CSS, czyli gdzie jest divlub, tdktóry ma klasę lub atrybut, itp., Abym mógł uzyskać ich HTML, kolor lub wartość, ale w AngularJS, przekonasz się, że tak myślisz: z jakim modelem mam do czynienia, ustawię wartość modelu na prawdziwą. Nie zastanawiasz się, czy widok odzwierciedlający tę wartość jest zaznaczony, czy znajduje się w tdelemencie (szczegóły, o których często trzeba pomyśleć w jQuery).

Dzięki manipulacjom DOM w AngularJS dodajesz dyrektywy i filtry, które możesz traktować jako prawidłowe rozszerzenia HTML.

Jeszcze jedna rzecz, której doświadczysz w AngularJS: w jQuery często wywołujesz funkcje jQuery, w AngularJS, AngularJS wywoła twoje funkcje, więc AngularJS „powie ci, jak robić rzeczy”, ale korzyści są tego warte, więc ucz się AngularJS zwykle oznacza poznanie tego, czego chce AngularJS lub tego, w jaki sposób AngularJS wymaga przedstawienia swoich funkcji i odpowiednio je wywoła. Jest to jedna z rzeczy, która sprawia, że ​​AngularJS jest strukturą, a nie biblioteką.

Samuel
źródło
46

To są bardzo ładne, ale długie odpowiedzi.

Podsumowując moje doświadczenia:

  1. Administratorzy i dostawcy (usługi, fabryki itp.) Służą do modyfikowania modelu danych, a nie HTML.
  2. HTML i dyrektywy określają układ i powiązanie z modelem.
  3. Jeśli chcesz współdzielić dane między kontrolerami, stwórz usługę lub fabrykę - są to singletony, które są współużytkowane przez aplikację.
  4. Jeśli potrzebujesz widżetu HTML, utwórz dyrektywę.
  5. Jeśli masz jakieś dane i próbujesz teraz zaktualizować HTML ... STOP! zaktualizuj model i upewnij się, że kod HTML jest powiązany z modelem.
Dan
źródło
45

jQuery to biblioteka manipulacji DOM.

AngularJS jest strukturą MV *.

W rzeczywistości AngularJS jest jednym z niewielu frameworków JavaScript MV * (wiele narzędzi JavaScript MVC nadal należy do biblioteki kategorii).

Będąc platformą, hostuje Twój kod i przejmuje na siebie decyzje o tym, co zadzwonić i kiedy!

Sam AngularJS zawiera w sobie edycję jQuery-lite. Dlatego w przypadku niektórych podstawowych operacji wyboru / manipulacji DOM tak naprawdę nie musisz dołączać biblioteki jQuery (oszczędza to wiele bajtów do uruchomienia w sieci).

AngularJS ma koncepcję „dyrektyw” do manipulacji DOM i projektowania komponentów interfejsu użytkownika wielokrotnego użytku, więc powinieneś go używać, gdy tylko poczujesz potrzebę robienia rzeczy związanych z manipulacją DOM (dyrektywy są tylko miejscem, w którym powinieneś pisać kod jQuery podczas korzystania z AngularJS).

AngularJS obejmuje pewną krzywą uczenia się (więcej niż jQuery :-).

-> Dla każdego programisty pochodzącego z jQuery, moją pierwszą radą byłoby „nauczyć się JavaScript jako języka pierwszej klasy, zanim przejdę do bogatego frameworka, takiego jak AngularJS!” Nauczyłem się powyższego faktu na własnej skórze.

Powodzenia.

Anand
źródło
34

To jabłka i pomarańcze. Nie chcesz ich porównywać. To dwie różne rzeczy. AngularJs ma już wbudowaną wersję jQuery lite, która pozwala wykonywać podstawowe manipulacje DOM bez włączania pełnej wersji jQuery.

jQuery polega na manipulacji DOM. To rozwiązuje wszystkie problemy z przeglądarkami, w przeciwnym razie będziesz musiał sobie z tym poradzić, ale nie jest to framework, który pozwala podzielić twoją aplikację na komponenty takie jak AngularJS.

Zaletą AngularJs jest to, że pozwala on oddzielić / odizolować manipulację DOM w dyrektywach. Dostępne są wbudowane dyrektywy, takie jak ng-click. Możesz tworzyć własne niestandardowe dyrektywy, które będą zawierały całą logikę widoku lub manipulację DOM, dzięki czemu nie skończysz mieszać kodu manipulacji DOM w kontrolerach lub usługach, które powinny zająć się logiką biznesową.

Angular dzieli twoją aplikację na - Kontrolery - Usługi - Widoki - itp.

i jest jeszcze jedna rzecz, to jest dyrektywa. Jest to atrybut, który możesz dołączyć do dowolnego elementu DOM i możesz szaleć z jQuery w nim zawartym, nie martwiąc się, że jQuery kiedykolwiek będzie w konflikcie ze składnikami AngularJs lub popsuć jego architekturę.

Słyszałem ze spotkania, w którym uczestniczyłem, jeden z założycieli Angular powiedział, że bardzo ciężko pracowali, aby oddzielić manipulację DOM, więc nie próbuj włączać ich ponownie.

Jin
źródło
31

Posłuchaj podcastu JavaScript Jabber: Episode # 32, który przedstawia oryginalnych twórców AngularJS: Misko Hevery i Igor Minar. Mówią dużo o tym, jak to jest przychodzić do AngularJS z innych środowisk JavaScript, zwłaszcza jQuery.

Jeden z punktów podcastu sprawił, że kliknąłem wiele rzeczy w odniesieniu do twojego pytania:

MISKO : [...] jedną z rzeczy, o których bardzo rzadko myśleliśmy w Angular, jest to, w jaki sposób zapewniamy wiele luków ratunkowych, abyś mógł się wydostać i po prostu znaleźć wyjście z tego. Tak więc dla nas odpowiedź brzmi „dyrektywy”. Dzięki dyrektywom w zasadzie stajesz się zwykłym małym JavaScriptem jQuery, możesz robić, co chcesz.

IGOR : Pomyśl więc o dyrektywie jako instrukcji kompilatora, która mówi jej za każdym razem, gdy natrafisz na ten określony element lub ten CSS w szablonie, i trzymasz ten rodzaj kodu, a ten kod jest odpowiedzialny za element i wszystko poniżej tego elementu w drzewie DOM.

Transkrypcja całego odcinka jest dostępna pod linkiem podanym powyżej.

Tak więc, aby bezpośrednio odpowiedzieć na twoje pytanie: AngularJS jest bardzo opiniotwórczy i jest prawdziwym frameworkiem MV *. Jednak nadal możesz robić wszystkie naprawdę fajne rzeczy, które znasz i kochasz za pomocą jQuery wewnątrz dyrektyw. To nie jest kwestia „jak zrobić to, co kiedyś w jQuery?” chodzi o to, jak „Jak uzupełnić AngularJS o wszystkie rzeczy, które robiłem w jQuery?”

To naprawdę dwa bardzo różne stany umysłu.

codevinsky
źródło
2
Nie jestem pewien, czy całkowicie zgodziłbym się, że Angular jest BARDZO przekonany. Chcesz mieć opinię, spójrz na Embera. Zobrazowałbym Angulara jako posiadającego opinie o złotych oczkach - przez większość tego, co widzę, jQuery ma zbyt mało opinii, a Ember ma zbyt wiele. Angular wydaje się w sam raz.
fool4jesus
30

Uważam to pytanie za interesujące, ponieważ moją pierwszą poważną ekspozycją na programowanie JavaScript był Node.js i AngularJS. Nigdy nie nauczyłem się jQuery i myślę, że to dobra rzecz, ponieważ nie muszę niczego się oduczać. W rzeczywistości aktywnie unikam rozwiązań jQuery dla moich problemów, a zamiast tego szukam tylko „sposobu AngularJS”, aby je rozwiązać. Sądzę więc, że moja odpowiedź na to pytanie sprowadzałaby się zasadniczo do „myślenia jak ktoś, kto nigdy nie nauczył się jQuery” i unikania pokusy bezpośredniego włączenia jQuery (oczywiście AngularJS używa go do pewnego stopnia za kulisami).

Evan Zamir
źródło
23

AngularJS i jQuery:

AngularJs i JQuery są zupełnie inne na każdym poziomie, z wyjątkiem funkcjonalności JQLite, a zobaczysz to, gdy zaczniesz uczyć się podstawowych funkcji AngularJs (wyjaśniłem to poniżej).

AngularJs to framework po stronie klienta, który oferuje budowę niezależnej aplikacji po stronie klienta. JQuery to biblioteka po stronie klienta, która bawi się wokół DOM.

Fajna zasada AngularJs - jeśli chcesz wprowadzić pewne zmiany w interfejsie użytkownika, pomyśl z perspektywy zmiany danych modelu. Zmień dane, a interfejs użytkownika zrenderuje się. Nie musisz za każdym razem bawić się w DOM, chyba że będzie to prawie wymagane, i że należy to również rozwiązać za pomocą dyrektyw Angular.

Aby odpowiedzieć na to pytanie, chcę podzielić się swoim doświadczeniem związanym z pierwszą aplikacją korporacyjną z AngularJS. Są to najbardziej niesamowite funkcje, które zapewnia Angular, gdy zaczynamy zmieniać nasze nastawienie do jQuery i otrzymujemy Angulara jako strukturę, a nie bibliotekę.

Dwukierunkowe wiązanie danych jest niesamowite: miałem siatkę ze wszystkimi funkcjami UPDATE, DELTE, INSERT. Mam obiekt danych, który wiąże model siatki za pomocą ng-repeat. Musisz tylko napisać jeden wiersz prostego kodu JavaScript do usunięcia i wstawienia i to wszystko. Siatka jest aktualizowana automatycznie, gdy model siatki zmienia się natychmiast. Aktualizacja działa w czasie rzeczywistym, bez kodu. Czujesz się niesamowicie!!!

Dyrektywy wielokrotnego użytku są super: pisz dyrektywy w jednym miejscu i używaj ich w całej aplikacji. O MÓJ BOŻE!!! Użyłem tej dyrektywy do stronicowania, wyrażeń regularnych, sprawdzania poprawności itp. To naprawdę fajne!

Routing jest silny: od implementacji zależy, w jaki sposób chcesz go używać, ale wymaga bardzo niewielu wierszy kodu, aby skierować żądanie podania kodu HTML i kontrolera (JavaScript)

Kontrolery są świetne: kontrolery dbają o swój własny HTML, ale ta separacja działa dobrze dla zwykłej funkcjonalności. Jeśli chcesz wywołać tę samą funkcję jednym kliknięciem przycisku na master HTML, po prostu napisz tę samą nazwę funkcji w każdym kontrolerze i napisz osobny kod.

Wtyczki: Istnieje wiele innych podobnych funkcji, takich jak wyświetlanie nakładki w aplikacji. Nie musisz pisać dla niego kodu, po prostu użyj wtyczki nakładki dostępnej jako nakładka wc, a to automatycznie zajmie się wszystkimi żądaniami XMLHttpRequest (XHR).

Idealny do architektury RESTful : Bycie kompletnym frameworkiem sprawia, że ​​AngularJS świetnie współpracuje z architekturą RESTful. Wywołanie interfejsów API REST CRUD jest bardzo łatwiejsze i

Usługi : pisz wspólne kody za pomocą usług i mniej kodu w kontrolerach. Do udostępniania wspólnych funkcji kontrolerom można używać usług.

Rozszerzalność : Angular rozszerzył dyrektywy HTML za pomocą dyrektyw kątowych. Napisz wyrażenia w html i oceń je w czasie wykonywania. Twórz własne dyrektywy i usługi i używaj ich w innym projekcie bez dodatkowego wysiłku.

Sanjeev Singh
źródło
20

Jako początkujący JavaScript MV * i skupiający się wyłącznie na architekturze aplikacji (nie ma to znaczenia po stronie serwera / klienta), z pewnością poleciłbym następujący zasób (którego jestem zaskoczony, nie wspomniano jeszcze): Wzory projektowania JavaScript , autor: Addy Osmani , jako wprowadzenie do różnych wzorców projektowych JavaScript . Terminy użyte w tej odpowiedzi pochodzą z dokumentu powiązanego powyżej. Nie zamierzam powtarzać tego, co było dobrze sformułowane w przyjętej odpowiedzi. Zamiast tego ta odpowiedź prowadzi do teoretycznych podstaw, które zasilają AngularJS (i inne biblioteki).

Podobnie jak ja, szybko zdasz sobie sprawę, że AngularJS (lub Ember.js , Durandal i inne frameworki MV *) to jedna złożona struktura gromadząca wiele różnych wzorców projektowych JavaScript.

Ułatwiłem także przetestowanie (1) natywnego kodu JavaScript i (2) mniejszych bibliotek dla każdego z tych wzorców osobno przed zanurzeniem się w jednym globalnym środowisku. Pozwoliło mi to lepiej zrozumieć, z jakimi kluczowymi zagadnieniami zajmuje się framework (ponieważ osobiście masz do czynienia z tym problemem).

Na przykład:

  • JavaScript Programowanie obiektowe (jest to link wyszukiwarki Google). To nie jest biblioteka, ale z pewnością warunek wstępny każdego programowania aplikacji. Nauczył mnie natywnych implementacji wzorów prototypów, konstruktorów, singletonów i dekoratorów
  • jQuery / Underscore dla wzoru fasady (jak WYSIWYG do manipulowania DOM)
  • Prototype.js dla wzorca prototyp / konstruktor / mieszanka
  • Wymagaj JS / Curl.js dla wzorca modułu / AMD
  • KnockoutJS za obserwowalny wzór publikowania / subskrybowania

NB: Ta lista nie jest kompletna ani „najlepsze biblioteki”; po prostu są to biblioteki, z których korzystałem. Te biblioteki zawierają również więcej wzorców, te wymienione są tylko ich głównymi celami lub oryginalnymi intencjami. Jeśli uważasz, że czegoś brakuje na tej liście, proszę wspomnij o tym w komentarzach, a chętnie go dodam.

Tyblitz
źródło
12

W rzeczywistości, jeśli używasz AngularJS, nie potrzebujesz jQuery. Sam AngularJS ma wiążącą i dyrektywę, która jest bardzo dobrym „zamiennikiem” większości rzeczy, które możesz zrobić z jQuery.

Zwykle tworzę aplikacje mobilne przy użyciu AngularJS i Cordova . Jedyną rzeczą, jakiej potrzebowałem z jQuery, jest Selektor.

Przeglądając go, widzę, że istnieje osobny moduł wyboru jQuery. To skwierczenie.

Postanowiłem zrobić mały fragment kodu, który pomoże mi szybko założyć stronę internetową przy użyciu AngularJS z mocą jQuery Selector (używając Sizzle).

Udostępniłem swój kod tutaj: https://github.com/huytd/Sizzular

Huy Tran
źródło