Cum să creați și să implementați aplicația de material unghiular
Publicat: 2022-03-10Angular este una dintre alegerile populare în timpul creării de noi aplicații web. Mai mult, specificațiile „Material Design” au devenit astăzi o alegere de preferat pentru a crea o experiență minimă și captivantă. Astfel, orice proiect nou „Angular” folosește în mare parte „Biblioteca de design de material angular” pentru a utiliza componentele care urmează specificațiile de proiectare a materialelor. De la animații fluide până la feedback-ul de interacțiune adecvat, toate acestea sunt deja disponibile ca parte a bibliotecii oficiale de design de materiale pentru angular.
După ce aplicația web este dezvoltată, următorul pas este implementarea acesteia. Aici intervine „Netlify” în imagine. Cu interfața sa foarte ușor de utilizat, implementarea automată, împărțirea traficului pentru testarea A/B și diverse alte caracteristici, Netlify este cu siguranță un instrument grozav.
Articolul va fi o prezentare a creării unei aplicații web Angular 8 folosind biblioteca oficială Angular Material Design. Vom crea o aplicație web generatoare de coduri QR bazată complet pe Angular în timp ce este găzduită pe Netlify.
Fișierele pentru acest tutorial pot fi găsite pe GitHub și o versiune demonstrativă este implementată aici.
Noțiuni de bază
- Instalați Angular 8,
- Creați un cont GitHub,
- Instalați Git pe computer,
- Creați un cont Netlify.
Notă : voi folosi VSCode și Microsoft Windows ca IDE și sistem de operare preferat, deși pașii ar fi similari pentru orice alt IDE pe orice alt sistem de operare.
După ce condițiile preliminare de mai sus sunt îndeplinite, să începem!
Batjocuri și planificare
Înainte de a începe crearea proiectului, ar fi benefic să planificăm în avans: Ce fel de interfață ne-am dori în aplicația noastră? Vor exista piese reutilizabile? Cum va interacționa aplicația cu serviciile externe?
În primul rând, verificați simularea UI.
Acestea sunt cele trei pagini diferite care vor fi conținute în aplicație. Pagina principală va fi punctul de plecare al aplicației noastre. Crearea unei pagini QR ar trebui să se ocupe de crearea unui nou cod QR. Pagina Istoric va afișa toate codurile QR salvate.
Modelele nu oferă doar o idee despre aspectul aplicației, dar separă și responsabilitatea fiecărei pagini.
O observație (din simulare) este că se pare că bara de navigare de sus este comună în toate paginile. Astfel, bara de navigare poate fi creată ca componentă reutilizabilă și reutilizată.
Acum că avem o idee destul de bună despre cum va arăta aplicația și ce poate fi refolosit, să începem.
Crearea unui nou proiect unghiular
Lansați VSCode, apoi deschideți o fereastră de terminal în VSCode pentru a genera un nou proiect Angular.
Terminalul se va deschide cu o cale implicită, așa cum se arată în prompt. Puteți trece la un director preferat înainte de a continua; în cazul Windows, voi folosi comanda cd
.
Mergând înainte, angular-cli are o comandă pentru a genera proiecte ng new <project-name>
. Folosiți orice nume de proiect care vă place și apăsați Enter, de exemplu, ng new qr
.
Aceasta va declanșa magia unghiulară-cli; va oferi câteva opțiuni pentru a configura unele aspecte ale proiectului, de exemplu, adăugarea de rutare unghiulară. Apoi, pe baza opțiunilor selectate, va genera întregul schelet al proiectului care poate fi rulat fără nicio modificare.
Pentru acest tutorial, introduceți Da pentru rutare și selectați CSS pentru stil. Aceasta va genera un nou proiect Angular:
Acum avem un proiect Angular complet funcțional. Pentru a ne asigura că totul funcționează corect, putem rula proiectul introducând această comandă în terminal: ng serve
. Uh, dar stai, asta duce la o eroare. Ce s-ar fi putut întâmpla?
Nu-ți face griji. Ori de câte ori creați un nou proiect folosind angular-cli, acesta generează întregul schelet în interiorul unui folder numit după numele proiectului specificat în comanda ng new qr
. Aici, va trebui să schimbăm directorul de lucru curent cu cel tocmai creat. În Windows, utilizați comanda cd qr
pentru a schimba directorul.
Acum, încercați să rulați din nou proiectul cu ajutorul ng serve
:
Deschideți un browser web, accesați adresa URL https://localhost:4200 pentru a vedea proiectul care rulează. Comanda ng serve
rulează aplicația pe portul 4200 în mod implicit.
SFAT : Pentru a-l rula pe un alt port, folosim comanda ng serve --port <any-port>
, de exemplu, ng serve --port 3000
.
Acest lucru asigură că proiectul nostru de bază Angular este în funcțiune. Să mergem mai departe.
Trebuie să adăugăm folderul de proiect la VSCode. Accesați meniul „Fișier” și selectați „Deschidere folder” și selectați folderul proiectului. Dosarul proiectului va fi afișat acum în vizualizarea Explorer din stânga.
Adăugarea bibliotecii de materiale unghiulare
Pentru a instala biblioteca de materiale Angular, utilizați următoarea comandă în fereastra terminalului: ng add @angular/material
. Acest lucru va pune (din nou) câteva întrebări, cum ar fi ce temă doriți, dacă doriți animații implicite, dacă este necesar suportul tactil, printre altele. Vom selecta doar tema implicită Indigo/Pink
, Yes
pentru adăugarea bibliotecii HammerJS
și a animațiilor browserului.
Comanda de mai sus configurează, de asemenea, întregul proiect pentru a permite suportul pentru componentele materiale.
- Acesta adaugă dependențe de proiect la package.json ,
- Acesta adaugă fontul Roboto la fișierul index.html ,
- Acesta adaugă fontul pictogramei Material Design la index.html dvs.,
- De asemenea, adaugă câteva stiluri CSS globale la:
- Îndepărtați marginile din corp,
- Setați
height: 100%
în HTML și body, - Setați Roboto ca font implicit al aplicației.
Doar pentru a fi sigur că totul este în regulă, puteți rula proiectul din nou în acest moment, deși nu veți observa nimic nou.
Adăugarea paginii de pornire
Scheletul proiectului nostru este acum gata. Să începem prin a adăuga pagina de pornire.
Vrem să menținem pagina noastră de pornire simplă, la fel ca în imaginea de mai sus. Această pagină de pornire folosește câteva componente de material unghiular. Să disecăm.
- Bara de sus este un element de
nav
HTML simplu, care conține un buton de stil material, butonmat-button
, cu o imagine și un text ca element secundar. Culoarea barei este aceeași cu culoarea primară care a fost selectată la adăugarea bibliotecii de materiale Angular; - O imagine centrată;
- Un alt,
mat-button
, cu doar un text drept copil. Acest buton va permite utilizatorilor să navigheze la pagina de istoric; - O insignă de numărare,
matBadge
, atașată butonului de mai sus, care arată numărul de coduri QR salvate de utilizator; - Un buton de acțiune plutitor,
mat-fab
, în colțul din dreapta jos, având culoarea de accent din tema selectată.
Digresând puțin, să adăugăm mai întâi alte componente și servicii necesare.
Adăugarea antetului
După cum a fost planificat anterior, bara de navigare ar trebui reutilizată, să o creăm ca o componentă unghiulară separată. Deschideți terminalul în VSCode și tastați ng gc header
(prescurtare de la ng generate component header) și apăsați Enter. Aceasta va crea un nou folder numit „header” care va conține patru fișiere:
- header.component.css : folosit pentru a oferi stil pentru această componentă;
- header.component.html : pentru adăugarea elementelor HTML;
- header.component.spec.ts : pentru scrierea cazurilor de testare;
- header.component.ts : pentru a adăuga logica bazată pe Typescript.
Pentru ca antetul să arate așa cum a fost în simulari, adăugați codul HTML de mai jos în header.component.html :
<nav class="navbar" [class.mat-elevation-z8]=true> <div> <button *ngIf="showBackButton" aria-hidden=false mat-icon-button routerLink="/"> <mat-icon> <i class="material-icons md-32">arrow_back</i> </mat-icon> </button> <span>{{currentTitle}}</span> </div> <button *ngIf="!showBackButton" aria-hidden=false mat-button class="button"> <img src="../../assets/qr-icon-white.png"> <span>QR Generator</span> </button> <button *ngIf="showHistoryNav" aria-hidden=false mat-button class="button" routerLink="/history"> <span>History</span> </button> </nav>
SFAT : Pentru a adăuga cotă pentru orice componentă de material, utilizați [class.mat-elevation-z8]=true
, valoarea cotei poate fi modificată prin schimbarea valorii z , în acest caz este z8
. De exemplu, pentru a schimba cota la 16, utilizați [class.mat-elevation-z16]=true
.
În fragmentul HTML de mai sus, sunt utilizate două elemente de material Angular: mat-icon
și mat-button/mat-icon-button
. Utilizarea lor este foarte simplă; mai întâi, trebuie să le adăugăm pe cele două ca module în app.module.ts , așa cum se arată mai jos:
Acest lucru ne va permite să folosim aceste două elemente de material unghiular oriunde în orice componentă.
Pentru adăugarea butoanelor de materiale, se utilizează următorul fragment HTML:
<button mat-button> Material Button </button>
Există diferite tipuri de elemente de buton de material disponibile în biblioteca de materiale Angular, cum ar fi mat-raised-button
mat-flat-button
mat-fab
și altele; doar înlocuiți butonul mat-button
din fragmentul de cod de mai sus cu orice alt tip.
Celălalt element este mat-icon
care este folosit pentru a afișa pictogramele disponibile în biblioteca de pictograme de material. Când biblioteca de materiale Angular a fost adăugată la început, apoi a fost adăugată și o referință la biblioteca de pictograme de material, ceea ce ne-a permis să folosim pictograme din gama largă de pictograme.
Utilizarea este la fel de simplă ca:
<mat-icon> <i class="material-icons md-32">arrow_back</i> </mat-icon>
Eticheta imbricată <i>
poate fi folosită pentru a modifica dimensiunea pictogramei (aici este md-32
), ceea ce va face ca dimensiunea pictogramei să fie de 32 px în înălțime și lățime. Această valoare poate fi md-24
, md-48
și așa mai departe. Valoarea etichetei imbricate <i>
este numele pictogramei. (Numele poate fi găsit aici pentru orice altă pictogramă.)
Accesibilitate
Ori de câte ori sunt utilizate pictograme sau imagini, este imperativ ca acestea să furnizeze suficiente informații în scopuri de accesibilitate sau pentru un utilizator de cititor de ecran. ARIA (Accessible Rich Internet Applications) definește o modalitate de a face conținutul web și aplicațiile web mai accesibile persoanelor cu dizabilități.
Un punct de remarcat este că elementele HTML care au semantica lor nativă (de ex. nav
) nu au nevoie de atribute ARIA; cititorul de ecran ar ști deja că nav
este un element de navigare și l-ar citi ca atare.
Specificațiile ARIA sunt împărțite în trei categorii: roluri, stări și proprietăți. Să presupunem că un div
este folosit pentru a crea o bară de progres în codul HTML. Nu are nicio semantică nativă; Rolul ARIA poate descrie acest widget ca o bară de progres, proprietatea ARIA poate indica caracteristica sa, cum ar fi poate fi tragetă. Starea ARIA va descrie starea sa curentă, cum ar fi valoarea curentă a barei de progres. Vedeți fragmentul de mai jos:
<div role="progressbar" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100"> </div>
În mod similar, este folosit un atribut aria foarte frecvent utilizat: aria-hidden=true/false
. Valoarea adevărată face ca elementul să fie invizibil pentru cititorii de ecran.
Deoarece majoritatea elementelor UI utilizate în această aplicație au semnificație semantică nativă, singurele atribute ARIA utilizate sunt pentru a specifica stările de vizibilitate ARIA. Pentru informații detaliate, consultați aceasta.
Header.component.html conține o anumită logică pentru a ascunde și afișa butonul înapoi, în funcție de pagina curentă. Mai mult, butonul Acasă conține și o imagine/logo care ar trebui adăugată în folderul /assets
. Descărcați imaginea de aici și salvați-o în folderul /assets
.
Pentru stilul barei de navigare, adăugați CSS de mai jos în header.component.css :
.navbar { position: fixed; top: 0; left: 0; right: 0; z-index: 2; background: #3f51b5; display: flex; flex-wrap: wrap; align-items: center; padding: 12px 16px; } .button { color: white; margin: 0px 10px; }
Deoarece dorim să păstrăm componenta antet reutilizabilă peste alte componente, astfel încât să decidem ce ar trebui să fie afișat, le vom solicita ca parametri de la alte componente. Acest lucru necesită utilizarea decoratorului @Input()
care se va lega de variabilele pe care le-am folosit în header.component.html .
Adăugați aceste linii în fișierul header.component.ts :
// Add these three lines above the constructor entry. @Input() showBackButton: boolean; @Input() currentTitle: string; @Input() showHistoryNav: boolean; constructor() { }
Cele trei legături de mai sus vor fi transmise ca parametru de la alte componente pe care le va folosi componenta antet. Utilizarea sa va fi mai clară odată ce vom merge mai departe.
Mergând mai departe, trebuie să creăm o pagină de pornire care poate fi reprezentată printr-o componentă Angular. Deci, să începem prin a crea o altă componentă; tastați ng gc home
în terminal pentru a genera automat componenta home. Ca și anterior, va fi creat un nou folder numit „acasă” care conține patru fișiere diferite. Înainte de a continua cu modificarea acelor fișiere, să adăugăm câteva informații de rutare la modulul de rutare unghiulară.
Adăugarea de rutare
Angular oferă o modalitate de a mapa URL-ul către o anumită componentă. Ori de câte ori are loc o navigare, cadrul Angular monitorizează URL-ul și pe baza informațiilor prezente în fișierul app-routing.module.ts ; inițializează componenta mapată. În acest fel, diferitele componente nu trebuie să-și asume responsabilitatea inițializării altor componente. În cazul nostru, aplicația are trei pagini navigabile făcând clic pe diferite butoane. Obținem acest lucru prin valorificarea suportului de rutare oferit de cadrul Angular.
Componenta de acasă ar trebui să fie punctul de plecare al aplicației. Să adăugăm aceste informații în fișierul app-routing.module.ts .
Proprietatea path
este setată ca șir gol; acest lucru ne permite să mapam adresa URL a aplicației la componenta paginii de pornire, ceva de genul google.com
care arată pagina de pornire Google.
SFAT : Valoarea căii nu începe niciodată cu „ /
”, ci folosește un șir gol, chiar dacă calea poate fi ca search/coffee
.
Revenind la componenta paginii de pornire, înlocuiți conținutul home.component.html cu acesta:
<app-header [showBackButton]="false" [currentTitle]=""></app-header> <app-profile></app-profile> <!-- FAB Fixed --> <button mat-fab class="fab-bottom-right" routerLink="/create"> <mat-icon> <i class="material-icons md-48">add</i> </mat-icon> </button>
Există trei părți pentru componenta acasă:
- Componenta antet reutilizabilă
<app-header>
, - Componenta profil
<app-profile>
, - Butonul de acțiune plutitor din dreapta jos.
Fragmentul HTML de mai sus arată cum este utilizată componenta antet reutilizabilă în alte componente; folosim doar selectorul de componente și trecem parametrii necesari.
Componenta de profil este creată pentru a fi folosită ca corp pentru pagina de pornire - o vom crea în curând.
Butonul de acțiune plutitor cu pictograma +
este un fel de buton de material unghiular de tip mat-fab
în partea dreaptă jos a ecranului. Are directiva de atribut routerLink
care utilizează informațiile despre rută furnizate în app-routing.module.ts
pentru navigare. În acest caz, butonul are valoarea traseului ca /create care va fi mapat pentru a crea componenta.
Pentru ca butonul de creare să plutească în dreapta jos, adăugați codul CSS de mai jos în home.component.css :
.fab-bottom-right { position: fixed; left: auto; bottom: 5%; right: 10%; }
Deoarece componenta de profil ar trebui să gestioneze corpul paginii de pornire, vom lăsa home.component.ts
intact.
Adăugarea componentei de profil
Deschideți terminalul, introduceți ng gc profile
și apăsați enter pentru a genera componenta profilului. După cum a fost planificat mai devreme, această componentă se va ocupa de corpul principal al paginii de pornire. Deschide profile.component.html
și înlocuiește conținutul acestuia cu acesta:
<div class="center profile-child"> <img class="avatar" src="../../assets/avatar.png"> <div class="profile-actions"> <button mat-raised-button matBadge="{{historyCount}}" matBadgeOverlap="true" matBadgeSize="medium" matBadgeColor="accent" color="primary" routerLink="/history"> <span>History</span> </button> </div> </div>
Fragmentul HTML de mai sus arată cum să utilizați elementul matBadge
al bibliotecii de materiale. Pentru a-l putea folosi aici, trebuie să urmăm exercițiul obișnuit de a adăuga MatBadgeModule
la fișierul app.module.ts
. Insignele sunt un mic descriptor de stare pictural pentru elementele UI, cum ar fi butoanele, pictogramele sau textele. În acest caz, este folosit cu un buton pentru a afișa numărul QR salvat de utilizator. Insigna bibliotecii de materiale unghiulare are diverse alte proprietăți, cum ar fi setarea poziției insigna cu matBadgePosition
, matBadgeSize
pentru a specifica dimensiunea și matBadgeColor
pentru a seta culoarea insigna.
Mai trebuie adăugat un element de imagine în dosarul cu materiale: Descărcare. Salvați același lucru în folderul /assets
al proiectului.
Deschide profile.component.css și adaugă asta:
.center { top: 50%; left: 50%; position: absolute; transform: translate(-50%, -50%); } .profile-child { display: flex; flex-direction: column; align-items: center; } .profile-actions { padding-top: 20px; } .avatar { border-radius: 50%; width: 180px; height: 180px; }
CSS-ul de mai sus va realiza UI așa cum a fost planificat.
Mergând mai departe, avem nevoie de un fel de logică pentru a actualiza valoarea istoricului, așa cum se va reflecta în matBadge
folosit mai devreme. Deschide profile.component.ts și adaugă următorul fragment corespunzător:
export class ProfileComponent implements OnInit { historyCount = 0; constructor(private storageUtilService: StorageutilService) { } ngOnInit() { this.updateHistoryCount(); } updateHistoryCount() { this.historyCount = this.storageUtilService.getHistoryCount(); } }
Am adăugat StorageutilService , dar nu am creat un astfel de serviciu până acum. Ignorând eroarea, am finalizat componenta noastră de profil, care completează și componenta paginii de pornire. Vom revizui această componentă a profilului după crearea serviciului nostru de utilitate de stocare. Bine, atunci hai să facem asta.
Stocare locală
HTML5 oferă o funcție de stocare web care poate fi utilizată pentru a stoca date local. Acest lucru oferă mult mai mult spațiu de stocare în comparație cu modulele cookie - cel puțin 5MB față de 4KB. Există două tipuri de stocare web cu domeniu de aplicare și durată de viață diferite: locală și sesiune . Primul poate stoca date în mod permanent, în timp ce al doilea este temporar și pentru o singură sesiune. Decizia de a selecta tipul poate fi bazată pe cazul de utilizare, în scenariul nostru dorim să salvăm peste sesiuni, așa că vom merge cu stocarea locală .
Fiecare parte de date este stocată într-o pereche cheie/valoare. Vom folosi textul pentru care este generat QR-ul ca cheie și imaginea QR codificată ca șir de caractere base64 ca valoare. Creați un folder de entitate, în interiorul folderului creați un nou fișier qr-object.ts și adăugați fragmentul de cod așa cum se arată:
Conținutul clasei:
export class QR { text: string; imageBase64: string; constructor(text: string, imageBase64: string) { this.imageBase64 = imageBase64; this.text = text; } }
Ori de câte ori utilizatorul salvează QR-ul generat, vom crea un obiect din clasa de mai sus și vom salva acel obiect utilizând serviciul utilitar de stocare.
Creați un nou folder de servicii, vom crea multe servicii, este mai bine să le grupăm împreună.
Schimbați directorul de lucru curent în servicii, cd services
, pentru a crea un serviciu nou, folosind ng gs <any name>
. Aceasta este o prescurtare pentru ng generate service <any name>
, tastați ng gs storageutil
și apăsați enter
Acest lucru va crea două fișiere:
- storageutil.service.ts
- storageutil.service.spec.ts
Acesta din urmă este pentru scrierea testelor unitare. Deschide storageutil.service.ts și adaugă asta:
private historyCount: number; constructor() { } saveHistory(key : string, item :string) { localStorage.setItem(key, item) this.historyCount = this.historyCount + 1; } readHistory(key : string) : string { return localStorage.getItem(key) } readAllHistory() : Array<QR> { const qrList = new Array<QR>(); for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i); const value = localStorage.getItem(key); if (key && value) { const qr = new QR(key, value); qrList.push(qr); } } this.historyCount = qrList.length; return qrList; } getHistoryCount(): number { if (this.historyCount) { return this.historyCount; } this.readAllHistory(); return this.historyCount; } deleteHistory(key : string) { localStorage.removeItem(key) this.historyCount = this.historyCount - 1; }
Importați clasa qr-object pentru a corecta orice erori. Pentru a utiliza caracteristica de stocare locală, nu este nevoie să importați ceva nou, doar folosiți cuvântul cheie localStorage
pentru a salva sau a obține valoare pe baza unei chei.
Acum deschideți din nou fișierul profile.component.ts și importați clasa StorageutilService
pentru a finaliza corect componenta de profil.
Derulând proiectul, putem vedea că pagina de pornire este așa cum a fost planificat.
Adăugarea Creați o pagină QR
Avem pagina noastră de pornire pregătită, deși butonul de creare/adăugare nu face nimic. Nu vă faceți griji, logica reală era deja scrisă. Am folosit o directivă routerLink
pentru a schimba calea de bază a adresei URL la /create
, dar nu a fost adăugată nicio mapare la fișierul app-routing.module.ts .
Să creăm o componentă care se va ocupa de crearea de noi coduri QR, tastați ng gc create-qr
și apăsați enter pentru a genera o nouă componentă.
Deschideți fișierul app-routing.module.ts și adăugați intrarea de mai jos la matricea de routes
:
{ path: 'create', component: CreateQrComponent },
Aceasta va mapa CreateQRComponent
cu adresa URL /create
.
Deschide create-qr.components.html și înlocuiește conținutul cu acesta:
<app-header [showBackButton]="showBackButton" [currentTitle]="title" [showHistoryNav]="showHistoryNav"></app-header> <mat-card class="qrCard" [class.mat-elevation-z12]=true> <div class="qrContent"> <!--Close button section--> <div class="closeBtn"> <button mat-icon-button color="accent" routerLink="/" matTooltip="Close"> <mat-icon> <i class="material-icons md-48">close</i> </mat-icon> </button> </div> <!--QR code image section--> <div class="qrImgDiv"> <img *ngIf="!showProgressSpinner" src={{qrCodeImage}} width="200px" height="200px"> <mat-spinner *ngIf="showProgressSpinner"></mat-spinner> <div class="actionButtons" *ngIf="!showProgressSpinner"> <button mat-icon-button color="accent" matTooltip="Share this QR"> <mat-icon> <i class="material-icons md-48">share</i> </mat-icon> </button> <button mat-icon-button color="accent" (click)="saveQR()" matTooltip="Save this QR"> <mat-icon> <i class="material-icons md-48">save</i> </mat-icon> </button> </div> </div> <!--Textarea to write any text or link--> <div class="qrTextAreaDiv"> <mat-form-field> <textarea matInput [(ngModel)]="qrText" cdkTextareaAutosize cdkAutosizeMinRows="4" cdkAutosizeMaxRows="4" placeholder="Enter a website link or any text..."></textarea> </mat-form-field> </div> <!--Create Button--> <div class="createBtnDiv"> <button class="createBtn" mat-raised-button color="accent" matTooltip="Create new QR code" matTooltipPosition="above" (click)="createQrCode()">Create</button> </div> </div> </mat-card>
Fragmentul de mai sus folosește multe dintre elementele bibliotecii de materiale Angular. După cum a fost planificat, are o referință de componentă antet în care sunt trecuți parametrii necesari. Următorul este corpul principal al paginii de creare; constă dintr-un card de material unghiular sau mat-card
centrat și ridicat până la 12px așa cum este [class.mat-elevation-z12]=true
.
Cardul de material este doar un alt tip de container care poate fi folosit ca orice altă etichetă div
. Deși biblioteca de materiale oferă unele proprietăți pentru a așeza informații bine definite într-un mat-card
cum ar fi plasarea imaginii, titlul, subtitrarea, descrierea și acțiunea, așa cum se poate vedea mai jos.
În fragmentul HTML de mai sus, am folosit mat-card
la fel ca orice alt container. Un alt element de bibliotecă de materiale folosit este matTooltip
; este doar un alt sfat explicativ cu ușurință de utilizare, afișat atunci când utilizatorul trece cu mouse-ul peste sau apasă lung pe un element. Folosiți doar fragmentul de mai jos pentru a afișa indicația:
matTooltip="Any text you want to show"
Poate fi folosit cu butoane pictograme sau orice alt element al interfeței de utilizare pentru a transmite informații suplimentare. În contextul aplicației, afișează informații despre butonul pictogramă de închidere. Pentru a schimba poziționarea balonului cu instrumente, se folosește matTooltipPosition
:
matTooltip="Any text you want to show" matTooltipPosition="above"
Pe lângă matTooltip
, mat-spinner
este folosit pentru a afișa progresul de încărcare. Când utilizatorul face clic pe butonul „Creare”, se efectuează un apel de rețea. Acesta este momentul în care este afișat rulantul de progres. Când apelul de rețea revine cu rezultat, ascundem doar rotorul. Poate fi folosit pur și simplu astfel:
<mat-spinner *ngIf="showProgressSpinner"></mat-spinner>
showProgressSpinner
este o variabilă booleană care este folosită pentru a arăta/a ascunde ruloul de progres. Biblioteca oferă, de asemenea, alți parametri, cum ar fi [color]='accent'
pentru a schimba culoarea, [mode]='indeterminate'
pentru a schimba tipul de rulare de progres. Un rotitor de progres nedeterminat nu va arăta progresul sarcinii, în timp ce unul determinat poate avea valori diferite pentru a reflecta progresul sarcinii. Aici, se folosește un spinner nedeterminat, deoarece nu știm cât timp va dura apelul de rețea.
Biblioteca de materiale oferă o variantă de textarea conformă cu ghidul de materiale, dar poate fi folosită numai ca descendent al mat-form-field
. Utilizarea zonei de text material este la fel de simplă ca cea implicită HTML, ca mai jos:
<mat-form-field> <textarea matInput placeholder="Hint text"></textarea> </mat-form-field>
matInput
este o directivă care permite etichetei native de input
să lucreze cu mat-form-field
. Proprietatea placeholder
permite adăugarea oricărui text indiciu pentru utilizator.
SFAT : Utilizați proprietatea cdkTextareaAutosize
textarea pentru a o face auto-redimensionabilă. Utilizați cdkAutosizeMinRows
și cdkAutosizeMaxRows
pentru a seta rânduri și coloane și toate trei împreună pentru a face ca zona de text să se redimensioneze automat până când atinge limita maximă de rânduri și coloane setată.
Pentru a folosi toate aceste elemente ale bibliotecii de materiale, trebuie să le adăugăm în fișierul app.module.ts .
Există o imagine substituent utilizată în HTML. Descărcați și salvați-l în folderul /assets
.
HTML-ul de mai sus necesită, de asemenea, stilul CSS, așa că deschideți fișierul create-qr.component.ts și adăugați următoarele:
.qrCard { display: flex; flex-direction: column; align-items: center; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 20%; height: 65%; padding: 50px 20px; } .qrContent { display: flex; flex-direction: column; align-items: center; width: 100%; } .qrTextAreaDiv { width: 100%; display: flex; flex-direction: row; justify-content: center; padding: 0px 0px; position: absolute; bottom: 10%; } .createBtn { left: 50%; transform: translate(-50%, 0px); width: 80%; } .createBtnDiv { position: absolute; bottom: 5%; width: 100%; } .closeBtn { display: flex; flex-direction: row-reverse; align-items: flex-end; width: 100%; margin-bottom: 20px; } .closeBtnFont { font-size: 32px; color: rgba(0,0,0,0.75); } .qrImgDiv { top: 20%; position: absolute; display: flex; flex-direction: column; align-items: center; justify-content: center; width: 100%; } .actionButtons { display: flex; flex-direction: row; padding-top: 20px; }
Să conectăm interfața de utilizare cu logică. Deschideți fișierul create-qr.component.ts și adăugați codul de mai jos, lăsând acele linii care sunt deja prezente:
export class CreateQrComponent implements OnInit { qrCodeImage = '../../../assets/download.png'; showProgressSpinner = false; qrText: string; currentQR; showBackButton = true; title = 'Generate New QR Code'; showHistoryNav = true; constructor(private snackBar: MatSnackBar, private restutil: RestutilService, private storageService: StorageutilService) { } ngOnInit() { } createQrCode() { //Check if any value is given for the qr code text if (!!this.qrText) { //Make the http call to load qr code this.loadQRCodeImage(this.qrText); } else { //Show snackbar this.showSnackbar('Enter some text first') } } public loadQRCodeImage(text: string) { // Show progress spinner as the request is being made this.showProgressSpinner = true; // Trigger the API call this.restutil.getQRCode(text).subscribe(image =>{ // Received the result - as an image blob - require parsing this.createImageBlob(image); }, error => { console.log('Cannot fetch QR code from the url', error) // Hide the spinner - show a proper error message this.showProgressSpinner = false; }); } private createImageBlob(image: Blob) { // Create a file reader to read the image blob const reader = new FileReader(); // Add event listener for "load" - invoked once the blob reading is complete reader.addEventListener('load', () => { this.qrCodeImage = reader.result.toString(); //Hide the progress spinner this.showProgressSpinner = false; this.currentQR = reader.result.toString(); }, false); // Read image blob if it is not null or undefined if (image) { reader.readAsDataURL(image); } } saveQR() { if (!!this.qrText) { this.storageService.saveHistory(this.qrText, this.currentQR); this.showSnackbar('QR saved') } else { //Show snackbar this.showSnackbar('Enter some text first') } } showSnackbar(msg: string) { //Show snackbar this.snackBar.open(msg, '', { duration: 2000, }); } }
Pentru a oferi utilizatorilor informații contextuale, folosim și MatSnackBar
din biblioteca de design de materiale. Acesta apare ca un pop-up de sub ecran și rămâne câteva secunde înainte de a dispărea. Acesta nu este un element, ci mai degrabă un serviciu care poate fi invocat din codul Typescript.
Fragmentul de mai sus cu numele metodei showSnackbar
arată cum să deschideți un snackbar, dar înainte de a putea fi utilizat, trebuie să adăugam intrarea MatSnackBar
în fișierul app.module.ts , așa cum am făcut pentru alte elemente ale bibliotecii de materiale.
SFAT : În versiunile recente ale bibliotecii de materiale Angular, nu există o modalitate simplă de a schimba stilul snackbar-ului. În schimb, trebuie să faceți două completări la cod.
Mai întâi, utilizați CSS-ul de mai jos pentru a modifica culorile de fundal și de prim-plan:
::ng-deep snack-bar-container.snackbarColor { background-color: rgba(63, 81, 181, 1); } ::ng-deep .snackbarColor .mat-simple-snackbar { color: white; }
În al doilea rând, utilizați o proprietate numită panelClass
pentru a seta stilul la clasa CSS de mai sus:
this.snackBar.open(msg, '', { duration: 2000, panelClass: ['snackbarColor'] });
Cele două combinații de mai sus vor permite un stil personalizat pentru componenta snackbar-ului bibliotecii de design de materiale.
Acest lucru completează pașii despre cum să creați o pagină QR, dar încă mai lipsește o bucată. Verificând fișierul create-qr.component.ts , va afișa o eroare cu privire la piesa lipsă. Piesa lipsă din acest puzzle este RestutilService
, care este responsabil pentru preluarea imaginii codului QR de la API-ul terță parte.
În terminal, schimbați directorul curent la servicii tastând ng gs restutil
și apăsând Enter. Acest lucru va crea fișierele RestUtilService. Deschideți fișierul restutil.service.ts și adăugați acest fragment:
private edgeSize = '300'; private BASE_URL = 'https://api.qrserver.com/v1/create-qr-code/?data={data}!&size={edge}x{edge}'; constructor(private httpClient: HttpClient) { } public getQRCode(text: string): Observable { // Create the url with the provided data and other options let url = this.BASE_URL; url = url.replace("{data}", text).replace(/{edge}/g, this.edgeSize); // Make the http api call to the url return this.httpClient.get(url, { responseType: 'blob' }); }
private edgeSize = '300'; private BASE_URL = 'https://api.qrserver.com/v1/create-qr-code/?data={data}!&size={edge}x{edge}'; constructor(private httpClient: HttpClient) { } public getQRCode(text: string): Observable { // Create the url with the provided data and other options let url = this.BASE_URL; url = url.replace("{data}", text).replace(/{edge}/g, this.edgeSize); // Make the http api call to the url return this.httpClient.get(url, { responseType: 'blob' }); }
Serviciul de mai sus preia imaginea QR din API-ul terță parte și, deoarece răspunsul nu este de tip JSON, ci o imagine, specificăm tipul de responseType
ca 'blob'
în fragmentul de mai sus.
Angular oferă clasa HttpClient
pentru a comunica cu orice server care acceptă HTTP. Oferă multe caracteristici, cum ar fi filtrarea cererii înainte de a fi lansată, recuperarea răspunsului, permițând procesarea răspunsului prin apeluri inverse și altele. Pentru a utiliza același lucru, adăugați o intrare pentru HttpClientModule în fișierul app.module.ts .
În cele din urmă, importați acest serviciu în fișierul create-qr.component.ts pentru a finaliza crearea codului QR.
Dar asteapta! Există o problemă cu logica QR de creare de mai sus. Dacă utilizatorul folosește același text pentru a genera QR-ul din nou și din nou, va avea ca rezultat un apel de rețea. O modalitate de a remedia acest lucru este stocarea în cache pe baza cererii, oferind astfel răspunsul din cache dacă textul solicitării este același.
Solicitare de stocare în cache
Angular oferă o modalitate simplificată de a efectua apeluri HTTP, HttpClient, împreună cu HttpInterceptors pentru a inspecta și transforma cererile sau răspunsurile HTTP către și de la servere. Poate fi folosit pentru autentificare sau stocare în cache și multe astfel de lucruri, mai mulți interceptori pot fi adăugați și legați în lanț pentru procesare ulterioară. În acest caz, interceptăm cereri și oferim răspunsul din cache dacă textul QR este același.
Creați un folder interceptor, apoi creați un fișier cache-interceptor.ts :
Adăugați fragmentul de cod de mai jos în fișier:
import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpResponse, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'; import { tap } from 'rxjs/operators'; import { of, Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class RequestCachingService implements HttpInterceptor { private cacheMap = new Map<string, HttpResponse<any>>(); constructor() { } intercept(req: HttpRequest , next: HttpHandler): Observable<HttpEvent<any>> { const cachedResponse = this.cacheMap.get(req.urlWithParams); if (cachedResponse) { return of(cachedResponse); } return next.handle(req).pipe(tap(event => { if (event instanceof HttpResponse) { this.cacheMap.set(req.urlWithParams, event); } })) } }
import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpResponse, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http'; import { tap } from 'rxjs/operators'; import { of, Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class RequestCachingService implements HttpInterceptor { private cacheMap = new Map<string, HttpResponse<any>>(); constructor() { } intercept(req: HttpRequest , next: HttpHandler): Observable<HttpEvent<any>> { const cachedResponse = this.cacheMap.get(req.urlWithParams); if (cachedResponse) { return of(cachedResponse); } return next.handle(req).pipe(tap(event => { if (event instanceof HttpResponse) { this.cacheMap.set(req.urlWithParams, event); } })) } }
În fragmentul de cod de mai sus, avem o hartă cu cheia fiind adresa URL a solicitării și răspunsul ca valoare. Verificăm dacă URL-ul curent este prezent în hartă; if it is, then return the response (the rest is handled automatically). If the URL is not in the map, we add it.
We are not done yet. An entry to the app.module.ts is required for its proper functioning. Add the below snippet:
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { CacheInterceptor } from './interceptor/cache-interceptor'; providers: [ { provide: HTTP_INTERCEPTORS, useClass: CacheInterceptor, multi: true } ],
This adds the caching feature to our application. Let's move on to the third page, the History page.
Adding The History Page
All the saved QR codes will be visible here. To create another component, open terminal type ng gc history
and press Enter.
Open history.component.css and add the below code:
.main-content { padding: 5% 10%; } .truncate { width: 90%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .center-img { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); display: flex; flex-direction: column; align-items: center; }
Open history.component.html and replace the content with this:
<app-header [showBackButton]="showBackButton" [currentTitle]="title" [showHistoryNav]="showHistoryNav"></app-header> <div class="main-content"> <mat-grid-list cols="4" rowHeight="500px" *ngIf="historyList.length > 0"> <mat-grid-tile *ngFor="let qr of historyList"> <mat-card> <img mat-card-image src="{{qr.imageBase64}}"> <mat-card-content> <div class="truncate"> {{qr.text}} </div> </mat-card-content> <mat-card-actions> <button mat-button (click)="share(qr.text)">SHARE</button> <button mat-button color="accent" (click)="delete(qr.text)">DELETE</button> </mat-card-actions> </mat-card> </mat-grid-tile> </mat-grid-list> <div class="center-img" *ngIf="historyList.length == 0"> <img src="../../assets/no-see.png" width="256" height="256"> <span>Nothing to see here</span> </div> </div>
As usual, we have the header component at the top. Then, the rest of the body is a grid list that will show all the saved QR codes as individual mat-card
. For the grid view, we are using mat-grid-list
from the Angular material library. As per the drill, before we can use it, we have to first add it to the app.module.ts file.
Lista grilă de mat acționează ca un container cu mai multe copii de plăci numite mat-grid-tile
. În fragmentul HTML de mai sus, fiecare țiglă este creată folosind mat-card
folosind unele dintre proprietățile sale pentru plasarea generică a altor elemente UI. Putem furniza number of columns
și rowHeight
, care este folosit pentru a calcula automat lățimea. În fragmentul de mai sus, oferim atât numărul de coloane, cât și valoarea rowHeight
.
Folosim o imagine de substituent atunci când istoricul este gol, descărcați-l și adăugați-l în folderul cu active.
Pentru a implementa logica pentru popularea tuturor acestor informații, deschideți fișierul history.component.ts și adăugați fragmentul de mai jos în clasa HistoryComponent
:
showBackButton = true; title = 'History'; showHistoryNav = false; historyList; constructor(private storageService: StorageutilService, private snackbar: MatSnackBar ) { } ngOnInit() { this.populateHistory(); } private populateHistory() { this.historyList = this.storageService.readAllHistory(); } delete(text: string) { this.storageService.deleteHistory(text); this.populateHistory(); } share(text: string) { this.snackbar.open(text, '', {duration: 2000,}) }
Logica de mai sus doar preia toate QR-urile salvate și populează pagina cu el. Utilizatorii pot șterge QR-ul salvat, care va șterge intrarea din stocarea locală.
Deci asta termină componenta noastră de istorie... sau nu? Mai trebuie să adăugăm maparea rutei pentru această componentă. Deschideți app-routing.module.ts și adăugați o mapare și pentru pagina de istorie:
{ path: 'history', component: HistoryComponent },
Întreaga matrice de rute ar trebui să arate astfel:
const routes: Routes = [ { path: '', component: HomeComponent }, { path: 'create', component: CreateQrComponent }, { path: 'history', component: HistoryComponent }, ];
Acum este un moment bun pentru a rula aplicația pentru a verifica fluxul complet, așa că deschideți terminalul și tastați ng serve
și apăsați Enter. Apoi, accesați localhost:4200
pentru a verifica funcționarea aplicației.
Adăugați în GitHub
Înainte de a trece la pasul de implementare, ar fi bine să adăugați proiectul într-un depozit GitHub.
- Deschideți GitHub.
- Creați un nou depozit.
- În VS Code, utilizați terminalul și urmați primul set de comenzi menționat în ghidul de pornire rapidă pentru a împinge toate fișierele de proiect.
Doar reîmprospătați pagina pentru a verifica dacă toate fișierele sunt vizibile. Din acest moment, orice modificări git (cum ar fi commit, pull/push) vor fi reflectate în acest depozit nou creat.
Netlify și implementare
Aplicația noastră rulează pe mașina noastră locală, dar pentru a le permite altora să o acceseze, ar trebui să o implementăm pe o platformă cloud și să o înregistrăm la un nume de domeniu. Aici intervine Netlify. Oferă servicii de implementare continuă, integrare cu GitHub și multe alte funcții de care să beneficiezi. În acest moment, dorim să activăm accesul global la aplicația noastră. Să începem.
- Înscrieți-vă pe Netlify.
- Din tabloul de bord, faceți clic pe butonul Site nou din Git .
- Faceți clic pe GitHub în ecranul următor.
- Autorizați Netlify să vă poată accesa depozitele GitHub.
- Căutați și selectați depozitul
qr
nou creat. - Netlify, în pasul următor, ne permite să alegem ramura depozitului GitHub pentru implementări. În mod normal, se folosește ramura
master
, dar se poate avea și o ramură derelease
separată care conține doar caracteristici stabile și legate de lansare.
Deoarece aceasta este o aplicație web Angular, adăugați ng build --prod
ca comandă de compilare. Directoarele publicate vor fi dist/qr
așa cum este menționat în fișierul angular.json
.
Acum faceți clic pe butonul Deploy site
care va declanșa o construcție de proiect cu comanda ng build --prod
și va scoate fișierul în dist/qr
.
Deoarece am furnizat informațiile despre cale către Netlify, acesta va prelua automat fișierele corecte pentru deservirea aplicației web. Netlify adaugă un domeniu aleatoriu aplicației noastre în mod implicit.
Acum puteți face clic pe linkul furnizat în pagina de mai sus pentru a accesa aplicația de oriunde. În cele din urmă, aplicația a fost implementată.
Domeniu personalizat
În imaginea de mai sus, adresa URL pentru aplicația noastră este afișată în timp ce subdomeniul este generat aleatoriu. Să schimbăm asta.
Faceți clic pe butonul Domain settings
apoi în secțiunea Domenii personalizate, faceți clic pe meniul cu 3 puncte și selectați Edit site name
.
Aceasta va deschide o fereastră pop-up în care poate fi introdus un nou nume de site; acest nume ar trebui să fie unic pe întregul domeniu Netlify. Introduceți orice nume de site disponibil și faceți clic pe Salvare .
Acum linkul către aplicația noastră va fi actualizat cu noul nume de site.
Testarea divizată
O altă caracteristică minunată oferită de Netlify este testarea divizată. Permite împărțirea traficului, astfel încât diferite seturi de utilizatori vor interacționa cu diferite implementări de aplicații. Putem adăuga funcții noi la o altă ramură și împărțim traficul către această desfășurare a sucursalei, putem analiza traficul și apoi îmbina ramura caracteristică cu ramura principală de implementare. Să o configuram.
Condiția prealabilă pentru activarea testării divizate este un depozit GitHub cu cel puțin două ramuri. Mergeți la depozitul de aplicații din GitHub care a fost creat mai devreme și creați o nouă ramură a
.
Depozitul va avea acum o ramură master
și a
ramură. Netlify trebuie configurat pentru a face implementări de ramuri, așa că deschideți tabloul de bord Netlify și faceți clic pe Settings
. În partea stângă, faceți clic pe Build & Deploy
, apoi Continuous Deployment
, apoi în partea dreaptă în secțiunea Deploy contexts
, faceți clic pe Edit settings
.
În subsecțiunea Branch deploys
, selectați opțiunea „Permiteți-mi să adaug ramuri individuale”, introduceți numele filialelor și salvați-o.
Implementarea bracelor este o altă caracteristică utilă oferită de Netlify; putem selecta ce ramuri de depozit GitHub să implementăm și, de asemenea, putem activa previzualizări pentru fiecare cerere de extragere către ramura master
înainte de fuzionare. Aceasta este o caracteristică bună care le permite dezvoltatorilor să-și testeze efectiv modificările în direct înainte de a adăuga modificările codului lor la ramura principală de implementare.
Acum, faceți clic pe opțiunea fila Split Testing
din partea de sus a paginii. Configurațiile de testare divizate vor fi prezentate aici.
Putem selecta ramura (alta decât ramura de producție) — în acest caz a
. Ne putem juca și cu setările de împărțire a traficului. Pe baza procentului de trafic alocat fiecărei ramuri, Netlify va redirecționa unii utilizatori către aplicația implementată folosind ramura a
, iar alții către ramificația master
. După configurare, faceți clic pe butonul Start test
pentru a activa împărțirea traficului.
SFAT : Este posibil ca Netlify să nu recunoască faptul că depozitul GitHub conectat are mai multe ramuri și poate da această eroare:
Pentru a rezolva acest lucru, trebuie doar să vă reconectați la depozit din opțiunile Build & Deploy
.
Netlify oferă și o mulțime de alte funcții. Tocmai am trecut prin câteva dintre caracteristicile sale utile pentru a demonstra ușurința de a configura diferite aspecte ale Netlify.
Acest lucru ne duce la sfârșitul călătoriei noastre. Am creat cu succes un design Angular Material bazat pe o aplicație web și l-am implementat pe Netlify.
Concluzie
Angular este un cadru grozav și popular pentru dezvoltarea de aplicații web. Cu biblioteca oficială de design de materiale Angular, este mult mai ușor să creați aplicații care să adere la specificațiile de proiectare a materialelor pentru o interacțiune foarte naturală cu utilizatorii. Mai mult, aplicația dezvoltată cu un cadru grozav ar trebui să folosească o platformă excelentă pentru implementare, iar Netlify este tocmai asta. Cu o evoluție constantă, un suport excelent și cu o multitudine de caracteristici, este cu siguranță o platformă grozavă pentru a aduce aplicații web sau site-uri statice în masă. Sperăm că acest articol vă va oferi ajutor în începerea unui nou proiect Angular, de la un gând până la implementare.
Lectură suplimentară
- Arhitectură unghiulară
- Mai multe componente de material unghiular
- Mai multe despre funcțiile Netlify