AngularJS vs. jQuery
AngularJS e jQuery adottano ideologie molto diverse. Se provieni da jQuery potresti trovare alcune delle differenze sorprendenti. L'angolare può farti arrabbiare.
Questo è normale, dovresti passare. Ne vale la pena.
La grande differenza (TLDR)
jQuery offre un toolkit per la selezione di bit arbitrari del DOM e per apportare modifiche ad hoc. Puoi fare praticamente tutto ciò che ti piace pezzo per pezzo.
AngularJS invece ti dà un compilatore .
Ciò significa che AngularJS legge l'intero DOM dall'alto verso il basso e lo tratta come codice, letteralmente come istruzioni per il compilatore. Mentre attraversa il DOM, cerca direttive specifiche ( direttive del compilatore) che indichino al compilatore AngularJS come comportarsi e cosa fare. Le direttive sono piccoli oggetti pieni di JavaScript che possono corrispondere a attributi, tag, classi o persino commenti.
Quando il compilatore angolare determina che un pezzo del DOM corrisponde a una particolare direttiva, chiama la funzione direttiva, passando l'elemento DOM, tutti gli attributi, l'attuale $ scope (che è un archivio di variabili locali) e alcuni altri bit utili. Questi attributi possono contenere espressioni che possono essere interpretate dalla direttiva e che indicano come renderizzarle e quando devono essere ridisegnate.
Le direttive possono quindi inserire componenti angolari aggiuntivi come controller, servizi, ecc. Ciò che emerge dal fondo del compilatore è un'applicazione Web completamente formata, cablata e pronta all'uso.
Ciò significa che Angular è Template Driven . Il tuo modello guida JavaScript, non viceversa. Si tratta di un'inversione radicale dei ruoli, e l'esatto contrario del discreto JavaScript che abbiamo scritto negli ultimi 10 anni circa. Questo può richiedere un po 'di tempo per abituarsi.
Se questo suona come potrebbe essere troppo prescrittivo e limitante, nulla potrebbe essere più lontano dalla verità. Poiché AngularJS tratta il codice HTML come codice, si ottiene una granularità a livello di HTML nell'applicazione Web . Tutto è possibile e la maggior parte delle cose è sorprendentemente facile quando fai qualche salto concettuale.
Passiamo al nocciolo della noia.
Innanzitutto, Angular non sostituisce jQuery
Angular e jQuery fanno cose diverse. AngularJS ti offre una serie di strumenti per produrre applicazioni web. jQuery offre principalmente strumenti per modificare il DOM. Se jQuery è presente sulla tua pagina, AngularJS la utilizzerà automaticamente. In caso contrario, AngularJS viene fornito con jQuery Lite, che è una versione ridotta, ma comunque perfettamente utilizzabile di jQuery.
A Misko piace jQuery e non si oppone al tuo utilizzo. Tuttavia, man mano che avanzi scoprirai che puoi svolgere praticamente tutto il tuo lavoro utilizzando una combinazione di ambito, modelli e direttive e dovresti preferire questo flusso di lavoro ove possibile perché il tuo codice sarà più discreto, più configurabile e altro Angolare.
Se usi jQuery, non dovresti spargerlo ovunque. Il posto corretto per la manipolazione del DOM in AngularJS è in una direttiva. Più su questi più tardi.
JavaScript discreto con selettori e modelli dichiarativi
jQuery viene generalmente applicato in modo discreto. Il tuo codice JavaScript è collegato nell'intestazione (o nel piè di pagina) e questo è l'unico posto in cui è menzionato. Usiamo i selettori per selezionare i bit della pagina e scrivere plugin per modificare quelle parti.
JavaScript ha il controllo. L'HTML ha un'esistenza completamente indipendente. Il tuo HTML rimane semantico anche senza JavaScript. Gli attributi di Onclick sono una pessima pratica.
Una delle prime cose che noterai su AngularJS è che gli attributi personalizzati sono ovunque . Il tuo HTML sarà disseminato di attributi ng, che sono essenzialmente attributi onClick sugli steroidi. Queste sono direttive (direttive del compilatore) e sono uno dei modi principali in cui il modello è agganciato al modello.
Quando lo vedi per la prima volta potresti essere tentato di scrivere AngularJS come JavaScript invadente della vecchia scuola (come ho fatto all'inizio). In effetti, AngularJS non gioca secondo queste regole. In AngularJS, HTML5 è un modello. È stato compilato da AngularJS per produrre la tua pagina web.
Questa è la prima grande differenza. Per jQuery, la tua pagina web è un DOM da manipolare. Per AngularJS, il tuo HTML è il codice da compilare. AngularJS legge in tutta la tua pagina web e la compila letteralmente in una nuova pagina web usando il suo compilatore incorporato.
Il modello dovrebbe essere dichiarativo; il suo significato dovrebbe essere chiaro semplicemente leggendolo. Utilizziamo attributi personalizzati con nomi significativi. Compiliamo nuovi elementi HTML, sempre con nomi significativi. Un designer con una conoscenza HTML minima e nessuna abilità di codifica può leggere il tuo modello AngularJS e capire cosa sta facendo. Lui o lei può apportare modifiche. Questa è la via angolare.
Il modello è al posto di guida.
Una delle prime domande che mi sono posto all'avvio di AngularJS e durante l'esecuzione dei tutorial è "Dov'è il mio codice?" . Non ho scritto JavaScript, eppure ho tutto questo comportamento. La risposta è ovvia Poiché AngularJS compila il DOM, AngularJS tratta il tuo HTML come codice. Per molti casi semplici è spesso sufficiente scrivere un modello e lasciare che AngularJS lo compili in un'applicazione per te.
Il tuo modello guida la tua applicazione. È trattato come un DSL . Scrivi i componenti di AngularJS e AngularJS si occuperà di inserirli e renderli disponibili al momento giusto in base alla struttura del modello. Questo è molto diverso da un modello MVC standard , in cui il modello è solo per l'output.
È più simile a XSLT che ad esempio Ruby on Rails .
Questa è una radicale inversione di controllo che richiede un po 'di tempo per abituarsi.
Smetti di provare a guidare la tua applicazione dal tuo JavaScript. Lascia che il modello guidi l'applicazione e che AngularJS si occupi del cablaggio dei componenti. Anche questa è la via angolare.
HTML semantico vs. modelli semantici
Con jQuery la tua pagina HTML dovrebbe contenere contenuti semantici significativi. Se JavaScript è disattivato (da un utente o motore di ricerca) i tuoi contenuti restano accessibili.
Perché AngularJS tratta la tua pagina HTML come modello. Il modello non dovrebbe essere semantico in quanto il contenuto è in genere archiviato nel modello che alla fine proviene dall'API. AngularJS compila il tuo DOM con il modello per produrre una pagina web semantica.
La tua sorgente HTML non è più semantica, invece, la tua API e il DOM compilato sono semantici.
In AngularJS, che significa vita nel modello, l'HTML è solo un modello, solo per la visualizzazione.
A questo punto probabilmente hai ogni sorta di domande riguardanti SEO e accessibilità, e giustamente. Ci sono problemi aperti qui. La maggior parte degli screen reader ora analizzerà JavaScript. I motori di ricerca possono anche indicizzare i contenuti AJAX . Tuttavia, vorrai assicurarti di utilizzare URL pushstate e di avere una sitemap decente. Vedi qui per una discussione del problema: https://stackoverflow.com/a/23245379/687677
Separazione delle preoccupazioni (SOC) vs. MVC
La separazione delle preoccupazioni (SOC) è un modello che è cresciuto in molti anni di sviluppo web per una serie di ragioni tra cui SEO, accessibilità e incompatibilità del browser. Sembra così:
- HTML - Significato semantico. L'HTML dovrebbe essere autonomo.
- CSS - Styling, senza CSS la pagina è ancora leggibile.
- JavaScript - Comportamento, senza lo script il contenuto rimane.
Ancora una volta, AngularJS non gioca secondo le loro regole. In un colpo solo, AngularJS elimina un decennio di saggezza ricevuta e invece implementa un modello MVC in cui il modello non è più semantico, nemmeno un po '.
Sembra così:
- Modello: i tuoi modelli contengono i tuoi dati semantici. I modelli sono generalmente oggetti JSON . I modelli esistono come attributi di un oggetto chiamato $ scope. Puoi anche memorizzare pratiche funzioni di utilità su $ scope a cui i tuoi modelli possono quindi accedere.
- Visualizza: le tue visualizzazioni sono scritte in HTML. La vista di solito non è semantica perché i tuoi dati risiedono nel modello.
- Controller: il controller è una funzione JavaScript che aggancia la vista al modello. La sua funzione è di inizializzare $ scope. A seconda dell'applicazione, potrebbe essere necessario o meno creare un controller. Puoi avere molti controller in una pagina.
MVC e SOC non si trovano su estremità opposte della stessa scala, ma su assi completamente diversi. SOC non ha senso in un contesto AngularJS. Devi dimenticarlo e andare avanti.
Se, come me, hai vissuto le guerre del browser, potresti trovare questa idea abbastanza offensiva. Superalo, ne varrà la pena, lo prometto.
Plugin vs. Direttive
I plugin estendono jQuery. Le direttive AngularJS estendono le funzionalità del tuo browser.
In jQuery definiamo i plugin aggiungendo funzioni a jQuery.prototype. Quindi li colleghiamo al DOM selezionando gli elementi e chiamando il plugin sul risultato. L'idea è di estendere le capacità di jQuery.
Ad esempio, se vuoi una giostra sulla tua pagina, potresti definire un elenco non ordinato di figure, magari avvolto in un elemento nav. È quindi possibile scrivere un po 'di jQuery per selezionare l'elenco sulla pagina e ripristinarlo come una galleria con timeout per eseguire l'animazione scorrevole.
In AngularJS, definiamo le direttive. Una direttiva è una funzione che restituisce un oggetto JSON. Questo oggetto indica ad AngularJS quali elementi DOM cercare e quali modifiche apportare ad essi. Le direttive sono agganciate al modello usando attributi o elementi, che inventi. L'idea è di estendere le capacità di HTML con nuovi attributi ed elementi.
Il modo AngularJS è quello di estendere le capacità dell'HTML nativo. Dovresti scrivere HTML che assomigli a HTML, esteso con attributi ed elementi personalizzati.
Se vuoi una giostra, usa semplicemente un <carousel />
elemento, quindi definisci una direttiva per inserire un modello e far funzionare quella ventosa.
Molte piccole direttive contro grandi plugin con switch di configurazione
La tendenza con jQuery è quella di scrivere grandi plugin di grandi dimensioni come lightbox che poi configuriamo passando in numerosi valori e opzioni.
Questo è un errore in AngularJS.
Prendi l'esempio di un menu a discesa. Quando si scrive un plug-in a discesa, si potrebbe essere tentati di codificare nei gestori dei clic, forse una funzione da aggiungere in un chevron che è su o giù, forse cambiare la classe dell'elemento spiegato, mostrare nascondere il menu, tutto ciò che è utile.
Fino a quando non si desidera apportare una piccola modifica.
Supponi di avere un menu che desideri aprire al passaggio del mouse. Bene, ora abbiamo un problema. Il nostro plugin ha collegato il nostro gestore di clic per noi, avremo bisogno di aggiungere un'opzione di configurazione per farlo funzionare diversamente in questo caso specifico.
In AngularJS scriviamo direttive più piccole. La nostra direttiva a discesa sarebbe ridicolmente piccola. Potrebbe mantenere lo stato piegato e fornire metodi per fold (), unfold () o toggle (). Questi metodi aggiornerebbero semplicemente $ scope.menu.visible che è un valore booleano che detiene lo stato.
Ora nel nostro modello possiamo collegarlo:
<a ng-click="toggle()">Menu</a>
<ul ng-show="menu.visible">
...
</ul>
Devi aggiornare al passaggio del mouse?
<a ng-mouseenter="unfold()" ng-mouseleave="fold()">Menu</a>
<ul ng-show="menu.visible">
...
</ul>
Il modello guida l'applicazione in modo da ottenere una granularità di livello HTML. Se vogliamo fare eccezioni caso per caso, il modello lo rende facile.
Chiusura vs. $ scope
I plugin JQuery vengono creati in una chiusura. La privacy è mantenuta all'interno di quella chiusura. Sta a te mantenere la catena di portata all'interno di quella chiusura. Hai davvero accesso solo al set di nodi DOM passati al plugin da jQuery, oltre a tutte le variabili locali definite nella chiusura e tutti i globi che hai definito. Ciò significa che i plugin sono abbastanza autonomi. Questa è una buona cosa, ma può diventare restrittiva quando si crea un'intera applicazione. Cercare di passare i dati tra le sezioni di una pagina dinamica diventa un lavoro ingrato.
AngularJS ha oggetti $ scope. Questi sono oggetti speciali creati e gestiti da AngularJS in cui memorizzi il tuo modello. Alcune direttive genereranno un nuovo $ scope, che per impostazione predefinita eredita dal suo $ scope avvolgente usando l'ereditarietà prototipica di JavaScript. L'oggetto $ scope è accessibile nel controller e nella vista.
Questa è la parte intelligente. Poiché la struttura dell'ereditarietà di $ scope segue approssimativamente la struttura del DOM, gli elementi hanno accesso al proprio ambito e a tutti gli ambiti contenenti senza soluzione di continuità, fino all'ambito $ scope globale (che non è lo stesso dell'ambito globale).
Ciò semplifica notevolmente il trasferimento dei dati e l'archiviazione dei dati a un livello appropriato. Se un menu a discesa è spiegato, solo il menu a discesa $ scope deve saperlo. Se l'utente aggiorna le sue preferenze, potresti voler aggiornare l'ambito $ $ globale e tutti gli ambiti nidificati che ascoltano le preferenze dell'utente verrebbero automaticamente avvisati.
Potrebbe sembrare complicato, infatti, una volta che ti rilassi, è come volare. Non è necessario creare l'oggetto $ scope, AngularJS crea un'istanza e la configura per te, in modo corretto e appropriato in base alla gerarchia dei modelli. AngularJS lo rende quindi disponibile per il tuo componente usando la magia dell'iniezione di dipendenza (ne parleremo più avanti).
Modifiche DOM manuali rispetto a Data Binding
In jQuery apporti manualmente tutte le modifiche al DOM. Costruisci nuovi elementi DOM a livello di codice. Se si dispone di un array JSON e si desidera inserirlo nel DOM, è necessario scrivere una funzione per generare l'HTML e inserirlo.
In AngularJS puoi farlo anche tu, ma sei incoraggiato a ricorrere all'associazione dei dati. Cambia il tuo modello e poiché il DOM è associato ad esso tramite un modello che il DOM si aggiornerà automaticamente, non è necessario alcun intervento.
Poiché l'associazione dei dati viene eseguita dal modello, utilizzando un attributo o la sintassi del parentesi graffa, è semplicissimo da eseguire. C'è un piccolo sovraccarico cognitivo ad esso associato, quindi ti ritroverai a farlo sempre.
<input ng-model="user.name" />
Associa l'elemento di input a $scope.user.name
. L'aggiornamento dell'input aggiornerà il valore nell'ambito corrente e viceversa.
Allo stesso modo:
<p>
{{user.name}}
</p>
produrrà il nome utente in un paragrafo. È un'associazione live, quindi se il $scope.user.name
valore viene aggiornato, verrà aggiornato anche il modello.
Ajax tutto il tempo
In jQuery effettuare una chiamata Ajax è abbastanza semplice, ma è ancora qualcosa a cui potresti pensare due volte. C'è una maggiore complessità a cui pensare e una buona dose di sceneggiatura da mantenere.
In AngularJS, Ajax è la tua soluzione predefinita e succede sempre, quasi senza che te ne accorga. Puoi includere modelli con ng-include. È possibile applicare un modello con la direttiva personalizzata più semplice. Puoi concludere una chiamata Ajax in un servizio e crearti un servizio GitHub o un servizio Flickr , a cui puoi accedere con una facilità sorprendente.
Oggetti di servizio e funzioni di supporto
In jQuery, se vogliamo svolgere una piccola attività non dom-dom come estrarre un feed da un'API, potremmo scrivere una piccola funzione per farlo nella nostra chiusura. Questa è una soluzione valida, ma cosa succede se vogliamo accedere a quel feed spesso? Cosa succede se vogliamo riutilizzare quel codice in un'altra applicazione?
AngularJS ci fornisce oggetti di servizio.
I servizi sono oggetti semplici che contengono funzioni e dati. Sono sempre dei singoli, il che significa che non può mai essercene più di uno. Supponiamo di voler accedere all'API Stack Overflow, potremmo scrivere un StackOverflowService
metodo che definisce i metodi per farlo.
Diciamo che abbiamo un carrello. Potremmo definire un ShoppingCartService che mantiene il nostro carrello e contiene metodi per aggiungere e rimuovere articoli. Poiché il servizio è un singleton ed è condiviso da tutti gli altri componenti, qualsiasi oggetto che è necessario può scrivere nel carrello e estrarre i dati da esso. È sempre lo stesso carrello.
Gli oggetti di servizio sono componenti AngularJS indipendenti che possiamo usare e riutilizzare a nostro piacimento. Sono semplici oggetti JSON contenenti funzioni e dati. Sono sempre singoli, quindi se si memorizzano i dati su un servizio in un posto, è possibile ottenere quei dati altrove semplicemente richiedendo lo stesso servizio.
Iniezione di dipendenza (DI) vs. Instatiation - alias de-spaghettification
AngularJS gestisce le tue dipendenze per te. Se vuoi un oggetto, fai semplicemente riferimento ad esso e AngularJS lo otterrà per te.
Fino a quando non inizierai a usarlo, è difficile spiegare che enorme vantaggio sia questo. Niente come AngularJS DI esiste all'interno di jQuery.
DI significa che invece di scrivere l'applicazione e collegarla insieme, si definisce invece una libreria di componenti, ognuno identificato da una stringa.
Supponiamo di avere un componente chiamato "FlickrService" che definisce i metodi per estrarre i feed JSON da Flickr. Ora, se voglio scrivere un controller in grado di accedere a Flickr, devo solo fare riferimento al 'FlickrService' per nome quando dichiaro il controller. AngularJS si occuperà di creare un'istanza del componente e renderlo disponibile al mio controller.
Ad esempio, qui definisco un servizio:
myApp.service('FlickrService', function() {
return {
getFeed: function() { // do something here }
}
});
Ora, quando voglio usare quel servizio, mi riferisco ad esso semplicemente come questo:
myApp.controller('myController', ['FlickrService', function(FlickrService) {
FlickrService.getFeed()
}]);
AngularJS riconoscerà che è necessario un oggetto FlickrService per creare un'istanza del controller e ce ne fornirà uno per noi.
Questo rende il cablaggio molto semplice e praticamente elimina qualsiasi tendenza alla spagettificazione. Abbiamo un elenco semplice di componenti e AngularJS ce li consegna uno per uno come e quando ne abbiamo bisogno.
Architettura di servizio modulare
jQuery dice molto poco su come dovresti organizzare il tuo codice. AngularJS ha opinioni.
AngularJS ti offre moduli in cui puoi inserire il tuo codice. Se stai scrivendo uno script che parla con Flickr, ad esempio, potresti voler creare un modulo Flickr per avvolgere tutte le tue funzioni relative a Flickr. I moduli possono includere altri moduli (DI). La tua applicazione principale di solito è un modulo e questo dovrebbe includere tutti gli altri moduli da cui dipenderà la tua applicazione.
Ottieni un semplice riutilizzo del codice, se vuoi scrivere un'altra applicazione basata su Flickr, puoi semplicemente includere il modulo Flickr e voilà, hai accesso a tutte le tue funzioni relative a Flickr nella tua nuova applicazione.
I moduli contengono componenti AngularJS. Quando includiamo un modulo, tutti i componenti in quel modulo diventano disponibili per noi come un semplice elenco identificato dalle loro stringhe uniche . Possiamo quindi iniettare quei componenti l'uno nell'altro usando il meccanismo di iniezione di dipendenza di AngularJS.
Per riassumere
AngularJS e jQuery non sono nemici. È possibile utilizzare jQuery in AngularJS molto bene. Se stai usando bene AngularJS (template, data binding, $ scope, direttive, ecc.) Scoprirai che hai bisogno di molto meno jQuery di quanto potresti altrimenti richiedere.
La cosa principale da capire è che il tuo modello guida la tua applicazione. Smetti di provare a scrivere grandi plugin che fanno tutto. Invece scrivi piccole direttive che fanno una cosa, quindi scrivi un semplice modello per collegarle.
Pensa meno a JavaScript discreto e pensa invece in termini di estensioni HTML.
Il mio piccolo libro
Ero così eccitato per AngularJS, ho scritto un breve libro su di esso che sei il benvenuto a leggere online http://nicholasjohnson.com/angular-book/ . Spero sia utile