Directivele sunt una dintre cele mai puternice componente ale AngularJS, ajutându-vă să extindeți elementele elementare HTML / atribute și să creați reutilizabile și testabile cod. În acest tutorial, vă voi arăta cum să utilizați directivele AngularJS cu cele mai bune practici din viața reală.
Ce vreau să spun aici directivăeste în mare parte direcții personalizate în timpul tutorialului. Nu voi încerca să vă învăț cum să utilizați directive încorporate cum ar fi ng-repeat
, ng-show
, etc. Vă voi arăta cum să utilizați directive personalizate pentru a crea propriile componente.
Să spunem că aveți o aplicație eCommerce despre cărți și că afișați anumite detalii ale cărților în mai multe domenii, cum ar fi comentariile, paginile de profil ale utilizatorilor, articolele etc. Widgetul pentru detaliile cărților poate fi la fel ca în cele de mai jos:
În acest widget există o imagine de carte, titlu, descriere, comentarii și evaluare. Colectarea acestor informații și introducerea într-un anumit element dom poate fi greu de făcut în orice loc pe care doriți să-l utilizați. Să vizualizăm această vizualizare utilizând o directivă AngularJS.
angular.module ("masteringAngularJsDirectives", []) .directive ("carte", functie () return restrict: 'E', domeniul: data: '=', templateUrl: 'templates / book-widget.html ')
O funcție de direcție a fost utilizată în exemplul de mai sus pentru a crea mai întâi o directivă. Numele directivei este carte
. Această directivă returnează un obiect și să vorbim puțin despre acest obiect. restrânge
este pentru definirea tipului de directivă și poate fi A
(Attribute),C
(Cfată), E
(EșiM
(coMMENT). Puteți vedea utilizarea fiecăreia dintre cele de mai jos.
Tip | folosire |
---|---|
A | carte> |
C | |
E | <carte date = "book_data">carte> |
M |
domeniu
este pentru gestionarea domeniului de aplicare a directivei. În cazul de mai sus, datele de carte sunt transferate în șablonul de directivă utilizând "="
tip de domeniu. Voi vorbi în detaliu despre domeniul de aplicare în următoarele secțiuni. templateUrl
este utilizat pentru apelarea unei vizualizări pentru a face conținut specific prin utilizarea datelor transferate în domeniul de aplicare al directivei. Puteți utiliza, de asemenea șablon
și să furnizeze direct codul HTML, după cum urmează:
... template: 'Cartea Info„...
În cazul nostru, avem o structură HTML complicată și de aceea am ales templateUrl
opțiune.
Directivele sunt definite în fișierul JavaScript al proiectului dvs. AngularJS și sunt utilizate în pagina HTML. Este posibil să utilizați directivele AngularJS în pagini HTML după cum urmează:
În această utilizare, numele directivei este utilizat în interiorul elementelor HTML standard. Să spuneți că aveți un meniu bazat pe roluri în aplicația dvs. de eCommerce. Acest meniu este format în funcție de rolul dvs. actual. Puteți defini o directivă pentru a decide dacă meniul curent trebuie afișat sau nu. Meniul dvs. HTML poate fi similar celui de mai jos:
și directiva după cum urmează:
(), function (restrict: A, link: function (scope, element, attrs) // Oare este verificat element.css ('display', 'none');)
Dacă utilizați restrâns
directivă în elementul de meniu ca atribut, puteți efectua o verificare a nivelului de acces pentru fiecare meniu. Dacă utilizatorul curent nu este autorizat, acel meniu nu va fi afișat.
Deci, ce este legătură
funcția acolo? Pur și simplu, funcția de legătură este funcția pe care o puteți utiliza pentru a efectua operații specifice directivei. Directiva nu numai că redă codul HTML, ci furnizează câteva intrări. De asemenea, puteți lega funcții la elementul direcțional, apela un serviciu și actualiza valoarea directivei, obțineți atribute directivă dacă este a E
tip de directivă etc.
Puteți utiliza numele directivei în clasele elementului HTML. Presupunând că veți folosi directiva de mai sus ca fiind C
, puteți actualiza directiva restrânge
la fel de C
și utilizați-l după cum urmează:
Fiecare element are deja o clasă pentru stil, și ca restrâns
se adaugă că este de fapt o directivă.
Nu este nevoie să utilizați o directivă în interiorul unui element HTML. Puteți crea propriul dvs. element utilizând o directivă AngularJS cu o E
restricţie. Să presupunem că aveți un widget utilizator în aplicația dvs. pentru a fi afișat nume de utilizator
, Avatar
, și reputatie
în mai multe locuri din aplicația dvs. Poate doriți să utilizați o astfel de directivă:
app.directive ("utilizator", functie () return restrict: 'E', link: function (scop, element, attrs) scope.username = attrs.username; scope.avatar = attrs.avatar; scope.reputation = attrs.reputation;, șablon: 'Nume utilizator: username, Avatar: avatar, Reputație: reputație')
Codul HTML va fi:
În exemplul de mai sus, se creează un element personalizat și se furnizează unele atribute nume de utilizator
, Avatar
, și reputatie
. Vreau să atrag atenția asupra corpului funcției de legătură. Elementele de atribut sunt atribuite domeniului directivei. Primul parametru al funcției de legătură este domeniul de aplicare al directivei actuale. Al treilea parametru al directivei este obiectul atribut al directivei, ceea ce înseamnă că puteți să citiți orice atribut din directiva personalizată prin utilizarea attrs.attr_name
. Valorile atributelor sunt atribuite domeniului de aplicare, astfel încât acestea să fie utilizate în interiorul șablonului.
De fapt, puteți face această operațiune într-un mod mai scurt, și voi vorbi mai târziu. Acest exemplu este pentru înțelegerea ideii principale din spatele utilizării.
Această utilizare nu este foarte comună, dar voi arăta cum să o folosesc. Să presupunem că aveți nevoie de un formular de comentarii pentru ca aplicația dvs. să fie utilizată în multe locuri. Puteți face acest lucru utilizând următoarea directivă:
app.directive ("comentariu", funcție () return restrict: 'M', șablon: '')
Și în elementul HTML:
Fiecare directivă are un domeniu de aplicare propriu, dar trebuie să aveți grijă cu privire la datele obligatorii cu declarația directivei. Să spuneți că implementați coş
parte din aplicația dvs. de eCommerce. Pe pagina de coș aveți elemente deja adăugate aici înainte. Fiecare element are câmpul cu suma pentru a selecta câte articole doriți să cumpărați, cum ar fi cele de mai jos:
Iată declarația directivei:
app.directive ("element", functie () return restrict: 'E', link: function (scope, element, attrs) scope.name =Nume: Nume Selectați Suma: Suma selectată: numara')
Și pentru a afișa trei elemente în HTML:
Problema aici este că ori de câte ori alegeți valoarea elementului dorit, toate secțiunile de cantitate ale elementelor vor fi actualizate. De ce? Deoarece există legături de date bidirecționale cu un nume numara
, dar domeniul de aplicare nu este izolat. Pentru a izola domeniul de aplicare, trebuie doar să adăugați domeniu:
la atributul directiv în secțiunea de returnare:
app.directive ("element", functie () return restrict: 'E', domeniul: , link: function (scope, element, attrs)Nume: Nume Selectați Suma: Suma selectată: numara')
Aceasta determină directiva dvs. să aibă propriul său domeniu de aplicare, astfel încât legăturile de date bidirecționale să se producă în interiorul acestei directive separat. Voi menționa, de asemenea, despre domeniu
atribut mai târziu.
Principalul avantaj al directivei este că este o componentă reutilizabilă care poate fi utilizată cu ușurință - puteți chiar furnizați câteva atribute suplimentare la această directivă. Dar, cum este posibil să se transmită o valoare suplimentară, obligatorie sau expresie directivei pentru ca datele să poată fi utilizate în interiorul directivei?
"@" Domeniu de aplicare: Acest tip de domeniu de aplicare este utilizat pentru transmiterea valorii în scopul directivei. Să presupunem că doriți să creați un widget pentru un mesaj de notificare:
app.controller ("MessageCtrl", function () $ scope.message = "Produsul a fost creat!";) app.directive ("notificare", function () return restrict: '@', șablon: 'mesaj');
și puteți folosi:
În acest exemplu, valoarea mesajului este pur și simplu atribuită domeniului directivei. Conținutul HTML redat va fi:
Produsul a fost creat!
"=" Domeniu de aplicare: În acest tip de domeniu, variabilele de domeniu sunt transmise în locul valorilor, ceea ce înseamnă că nu vom trece mesaj
, noi vom trece mesaj
in schimb. Motivul din spatele acestei caracteristici este construirea unei legături de date bidirecționale între directivă și elementele de pagină sau controlorii. Să o vedem în acțiune.
.directivă ("bookComment", funcția () return restrict: 'E', domeniul: text: '='')
În această directivă, încercăm să creăm un widget pentru afișarea textului de comentariu pentru a face un comentariu pentru o anumită carte. După cum puteți vedea, această directivă necesită un atribut text
pentru a construi legături de date bidirecționale între alte elemente din pagini. Puteți folosi acest lucru pe pagină:
Acesta este caseta de text a directivei
Acest lucru va arăta pur și simplu o casetă de text pe pagină, deci să adăugăm ceva mai mult pentru a interacționa cu această directivă:
Acesta este caseta de text din pagină
Acesta este caseta de text a directivei
Ori de câte ori introduceți ceva în prima casetă de text, va fi tastat și în a doua casetă de text. Puteți face acest lucru invers. În directivă am depășit variabila de domeniu commentText
în loc de valoare, iar această variabilă este referința obligatorie la prima casetă de text.
"&" Domeniu de aplicare: Suntem capabili să trecem valoarea și trimiterea la directive. În acest tip de domeniu vom examina cum să trecem expresii la directivă. În cazurile din viața reală, este posibil să trebuiască să transmiteți o anumită funcție (expresie) directivelor pentru a preveni cuplarea. Uneori, directivele nu trebuie să știe prea multe despre ideea din spatele acestor expresii. De exemplu, o directivă vă va plăcea cartea pentru dvs., dar nu știe cum să facă acest lucru. Pentru a face acest lucru, puteți urma o structură de genul:
.directivă ("likeBook", funcția () return restrict: 'E', domeniul: like: '&', template:')
În această directivă, o expresie va fi transmisă butonului directivei prin ca
atribut. Să definim o funcție în controler și să o transmitem directivei în interiorul HTML-ului.
$ scope.likeFunction = function () alertă ("Îmi place cartea!")
Acesta va fi în interiorul controlerului, iar șablonul va fi:
likeFunction ()
vine de la operator și este transmis directivei. Ce se întâmplă dacă doriți să treceți la un parametru likeFunction ()
? De exemplu, este posibil să trebuiască să transmiteți o valoare de rating către likeFunction ()
. Este foarte simplu: adăugați doar un argument funcției din interiorul controlerului și adăugați un element de intrare la directivă pentru a solicita numărătoarea de pornire de la utilizator. Puteți face acest lucru după cum se arată mai jos:
.directivă ("likeBook", funcția () return restrict: 'E', domeniul: like: '&', template:
"+"')
$ scope.likeFunction = funcție (stea) alertă ("Îmi place cartea !, și a dat stele" + star + ".)
După cum puteți vedea, caseta de text vine de la directivă. Valoarea casetei de text este legată de argumentul funcției cum ar fi (star: starCount)
. stea
este pentru funcția controlerului și starCount
pentru legarea valorii cutiei de text.
Uneori, este posibil să aveți o funcție care există în mai multe directive. Acestea pot fi introduse într-o directivă parentală, astfel încât acestea să fie moștenite de directivele privind copiii.
Permiteți-mi să vă dau un exemplu din viața reală. Doriți să trimiteți date statistice ori de câte ori clienții își mută cursorul mouse-ului în partea de sus a unei anumite cărți. Puteți implementa un eveniment cu click de mouse pentru directiva cărții, dar ce se întâmplă dacă va fi utilizat de o altă directivă? În acest caz, puteți utiliza moștenirea directivelor de mai jos:
app.directive ('mouseClicked', funcția () return restrict: 'E', domeniul: , controler: "MouseClickedCtrl ca mouseClicked"
Aceasta este o directivă parentală care urmează să fie moștenită de directivele privind copiii. După cum puteți vedea, există un atribut de controler al directivei utilizând directiva "ca". De asemenea, definim acest controler:
app.controller ('MouseClickedCtrl', functie ($ element) var mouseClicked = this; mouseClicked.bookType = null; mouseClicked.setBookType = function (type) mouseClicked.bookType = type; $ element.bind function () alert ("Tipul cartii:" + mouseClicked.bookType + "trimis pentru analiza statistica!");))
În acest controler, setăm pur și simplu o instanță a controlerului variabilei bookType
prin utilizarea directivelor privind copilul. Ori de câte ori faceți clic pe o carte sau o revistă, tipul elementului va fi trimis serviciului back-end (am folosit o funcție de alertă doar pentru a afișa datele). Cum vor putea directivele copil să utilizeze această directivă?
app.directive ('ebook', function () return necesita: mouseClicked, link: function (scope, element, attrs, mouseClickedCtrl) mouseClickedCtrl.setBookType ("EBOOK" (mouse-click), link: function (scop, element, attrs, mouseClickedCtrl) mouseClickedCtrl.setBookType ("MAGAZINE");)
După cum puteți vedea, directivele copilului utilizează necesita
cuvinte cheie pentru a utiliza directiva parentală. Un alt punct important este al patrulea argument al funcției de legătură din directivele copilului. Acest argument se referă la atributul controler al directivei părinte, care înseamnă că directiva copil poate folosi funcția de controler setBookType
în interiorul controlerului. Dacă elementul curent este o carte electronică, puteți utiliza prima directivă și, dacă este o revistă, puteți utiliza cea de-a doua:
Joc de tronuri (faceți clic pe mine)
PC World (faceți clic pe mine)
Regulile copilului sunt ca o proprietate a directivei părinte. Am eliminat folosirea evenimentului mouse-click pentru fiecare directivă a copilului prin plasarea acelei secțiuni în directiva parentală.
Când utilizați directive în interiorul șablonului, ceea ce vedeți pe pagină este versiunea compilată a directivei. Uneori, doriți să vedeți utilizarea actuală a directivei în scopul depanării. Pentru a vedea versiunea necomplicată a secțiunii curente, puteți utiliza ng-non-Bindable
. De exemplu, să presupunem că aveți un widget care imprimă cele mai populare cărți și aici este codul pentru care:
Variabila scopului cărții vine de la controler, iar rezultatul este următorul:
Dacă doriți să cunoașteți utilizarea directivei în spatele acestei ieșiri compilate, puteți utiliza această versiune a codului:
De data aceasta ieșirea va fi ca mai jos:
Este răcit până acum, dar ce se întâmplă dacă vrem să vedem ambele versiuni necompilate și compilate ale widget-ului? Este timpul să scrieți o directivă personalizată care va face o operație avansată de depanare.
app.directive ('customDebug', functie ($ compile) retur terminal: true, link: function (scope, element) var var.Element = element.clone () customEdit.removeAttr newElement = $ compile (currentElement) (domeniu); element.atter ("style"; border: 1px solid red); element.after (newElement);
În această directivă, clonăm elementul care este în modul de depanare, astfel încât să nu se schimbe după un anumit set de operații. După clonare, eliminați personalizate-depanare
directivă pentru a nu acționa ca un mod de depanare și apoi ao compila $ complile
, care este deja injectat în directivă. Am oferit un stil elementului modului de depanare pentru a sublinia cel defect. Rezultatul final va fi următorul:
Puteți salva timpul de dezvoltare utilizând acest tip de directivă de depanare pentru a detecta cauza principală a oricărei erori în proiectul dvs..
După cum știți deja, testarea unităților este o parte foarte importantă a dezvoltării pentru a controla total codul pe care l-ați scris și pentru a preveni posibilele bug-uri. Nu mă voi abate adânc în testarea unitară, dar vă voi da un indiciu despre modul de testare a directivelor în câteva moduri.
Voi folosi Jasmine pentru unitatea de testare și Karma pentru unitatea de test runner. Pentru a utiliza Karma, pur și simplu instalați-l la nivel global prin rulare npm instalare -g karma karma-cli
(trebuie să aveți Node.js și npm instalate pe computer). După instalare, deschideți linia de comandă, accesați directorul rădăcină de proiect și tastați karma init
. Va va pune cateva intrebari ca in cele ce urmeaza pentru a va stabili cerintele de testare.
Folosesc Webstorm pentru dezvoltare, și dacă utilizați Webstorm, faceți clic dreapta pe karma.conf.js și selectați Alerga karma.conf.js. Aceasta va executa toate testele configurate în karma conf. De asemenea, puteți rula teste cu karma începe
linie de comandă în dosarul rădăcină al proiectului. Asta e totul despre configurarea mediului, așa că trecem la partea de testare.
Să spunem că vrem să testăm directiva privind carte. Când trecem un titlu la directivă, acesta trebuie compilat într-o vizualizare detaliată a cărților. Deci sa începem.
descrie ("Test de carte", functie () var element; var domeniu; înainteEach (modul ("masteringAngularJsDirectives")) înainteEach (injectare ($ compile, $ rootScope) scope = $ rootScope; element = angular.element ""), compilați (element) ($ rootScope) domeniul $ digest ())); acesta (" direcția ar trebui compilată cu succes ", funcția () expect (element.html () );
În testul de mai sus, testează o nouă directivă numită booktest
. Această directivă are argumente titlu
și creează un div folosind acest titlu. În cadrul testului, înainte de fiecare secțiune de testare, sunăm modulul nostru masteringAngularJsDirectives
primul. Apoi, generăm o directivă numită booktest
. În fiecare etapă de testare, va fi testată producția directivei. Acest test este doar pentru o verificare a valorii.
În această secțiune, vom testa domeniul de aplicare al directivei booktest
. Această directivă generează o vizualizare detaliată a cărților pe pagină, iar atunci când faceți clic pe această secțiune detaliată, o variabilă de domeniu numită vizualizate
va fi setat ca Adevărat
. În testul nostru, vom verifica dacă vizualizate
este setat la true când evenimentul clic este declanșat. Directiva este:
.directivă ('booktest', funcția () return restrict: 'E', domeniul: title: '@', replace: true, template:titlu', link: function (scop, element, attrs) element.bind ("click", function () console.log; )
Pentru a seta un eveniment la un element din AngularJS în interiorul directivei, puteți utiliza legătură
atribut. În interiorul acestui atribut, aveți elementul curent, legat direct de un eveniment de clic. Pentru a testa această directivă, puteți folosi următoarele:
descrie ("Test de carte", functie () var element; var domeniu; înainteEach (modul ("masteringAngularJsDirectives")) înainteEach (injectare ($ compile, $ rootScope) scope = $ rootScope; element = angular.element "") ());) ()) ()) ()) ()) ()) $ compile (element) ($ rootScope) element.isolateScope () vizualizat). toBe (adevărat);););
În secțiunea de testare, se utilizează un eveniment de clic element.triggerHandler ( "clic")
. Când se declanșează un eveniment clic, variabila vizualizată trebuie setată ca Adevărat
. Această valoare este confirmată prin utilizarea se așteaptă (element.isolateScope (). vizualizate) .toBe (true)
.
Pentru a dezvolta proiecte web modulare și testabile, AngularJS este cel mai bun în comun. Directivele reprezintă una dintre cele mai bune componente ale AngularJS, ceea ce înseamnă că cu cât știți mai multe despre directivele AngularJS, cu atât mai multe proiecte modulare și testabile pe care le puteți dezvolta.
În acest tutorial, am încercat să vă arăt cele mai bune practici din viața reală despre directive și să rețineți că trebuie să faceți o mulțime de exerciții pentru a înțelege logica din spatele directivelor. Sper că acest articol vă ajută să înțelegeți bine directivele AngularJS.