網(wǎng)站建網(wǎng)站建站專業(yè)公司seo短期課程
本文還有配套的精品資源,點(diǎn)擊獲取
簡(jiǎn)介:Angular 11是Google支持的前端框架,適合構(gòu)建復(fù)雜的單頁(yè)應(yīng)用(SPA)。本課程將深入介紹Angular核心特性,如組件化、依賴注入、數(shù)據(jù)綁定和路由,并且涵蓋Angular 11的新特性,例如CLI改進(jìn)、RxJS 6.6和Ivy編譯器。通過(guò)實(shí)踐項(xiàng)目,學(xué)生將學(xué)會(huì)如何操作源碼文件、模板和樣式文件,進(jìn)而熟練掌握Angular開發(fā)。
1. Angular 11核心特性介紹
Angular 11作為當(dāng)前流行的前端框架之一,自推出以來(lái)就以其強(qiáng)大的功能和組件化開發(fā)模式受到開發(fā)者的青睞。在這一章節(jié)中,我們將一探究竟,為你詳細(xì)解析Angular 11的最新核心特性,以及這些特性如何提高開發(fā)效率和用戶體驗(yàn)。
1.1 Angular 11的核心改進(jìn)
Angular 11帶來(lái)了一系列的改進(jìn),包括對(duì)構(gòu)建工具鏈的優(yōu)化,對(duì)類型檢查的加強(qiáng),以及在性能上的進(jìn)一步提升。開發(fā)團(tuán)隊(duì)圍繞著“更快、更小、更容易維護(hù)”的目標(biāo),對(duì)框架進(jìn)行了多方面的優(yōu)化。
1.2 增強(qiáng)的TypeScript支持
Angular 11加強(qiáng)了與TypeScript的集成,為開發(fā)者提供了更為穩(wěn)定的類型推斷和代碼編輯體驗(yàn)。這得益于TypeScript版本的更新,使得TypeScript在Angular中的表現(xiàn)更加出色。
1.3 Ivy編譯器的新進(jìn)展
Ivy編譯器作為Angular 11的亮點(diǎn)之一,已經(jīng)進(jìn)入到了默認(rèn)啟用的狀態(tài)。Ivy編譯器優(yōu)化了編譯后的代碼,使得應(yīng)用的大小更小,啟動(dòng)速度更快,并且提供了更好的調(diào)試體驗(yàn)。
在下一章中,我們將深入了解Angular組件化開發(fā)和組織的各個(gè)方面,學(xué)習(xí)如何構(gòu)建和優(yōu)化Angular應(yīng)用的內(nèi)部結(jié)構(gòu)。
2. 組件化開發(fā)和組織
2.1 組件化的基礎(chǔ)概念
2.1.1 組件的定義和作用
在Angular中,組件是構(gòu)成應(yīng)用界面的基礎(chǔ)單元。組件通常由以下幾個(gè)部分組成:
- 一個(gè)帶有
@Component
裝飾器的TypeScript類 - 一個(gè)CSS樣式表,定義該組件的樣式
- 一個(gè)HTML模板,描述該組件的界面結(jié)構(gòu)
組件的作用可以歸納為以下幾點(diǎn):
- 封裝性 :每個(gè)組件可以獨(dú)立開發(fā)、測(cè)試和維護(hù),提供了良好的代碼封裝性。
- 復(fù)用性 :通過(guò)組件化,可以將界面的不同部分抽象成可復(fù)用的組件。
- 模塊化 :組件的使用促進(jìn)了模塊化開發(fā),有助于簡(jiǎn)化復(fù)雜應(yīng)用的結(jié)構(gòu)。
2.1.2 組件的生命周期鉤子
Angular為組件的生命周期提供了一組鉤子方法,可以在組件的不同生命周期階段執(zhí)行相應(yīng)的邏輯:
-
ngOnChanges()
:當(dāng)輸入屬性的值發(fā)生變化時(shí)調(diào)用。 -
ngOnInit()
:組件初始化時(shí)調(diào)用,通常用于設(shè)置初始狀態(tài)。 -
ngDoCheck()
:每次變更檢測(cè)周期開始時(shí)調(diào)用,用于檢查和處理變化。 -
ngAfterContentInit()
:將外部?jī)?nèi)容投影到組件視圖后調(diào)用。 -
ngAfterContentChecked()
:每次完成投影內(nèi)容的變更檢測(cè)后調(diào)用。 -
ngAfterViewInit()
:組件視圖初始化后調(diào)用。 -
ngAfterViewChecked()
:每次完成組件視圖的變更檢測(cè)后調(diào)用。 -
ngOnDestroy()
:組件銷毀前調(diào)用,用于清理工作,如取消訂閱事件。
2.2 組件間的通信機(jī)制
2.2.1 父子組件通信
在Angular中,父子組件之間的通信主要通過(guò)輸入(Input)和輸出(Output)屬性來(lái)實(shí)現(xiàn)。
- Input屬性 :使用
@Input()
裝飾器可以定義一個(gè)父組件向子組件傳遞數(shù)據(jù)的屬性。 - Output屬性 :使用
@Output()
裝飾器可以定義一個(gè)子組件向父組件發(fā)送事件的屬性,通常與EventEmitter
一起使用。
示例代碼:
// 子組件ChildComponent.ts
import { Component, Input, Output, EventEmitter } from '@angular/core';@Component({selector: 'app-child',template: `<p>{{ childMessage }}</p>`
})
export class ChildComponent {@Input() parentMessage: string; // 父組件傳入的屬性@Output() childChanged = new EventEmitter<string>(); // 事件發(fā)射器changeMessage() {this.childChanged.emit('Message changed from child component');}
}
// 父組件ParentComponent.ts
import { Component } from '@angular/core';@Component({selector: 'app-parent',template: `<app-child [parentMessage]="messageFromParent" (childChanged)="handleChildChange($event)"></app-child>`
})
export class ParentComponent {messageFromParent = 'Hello from parent!';handleChildChange(event: string) {console.log(event); // 接收到子組件傳來(lái)的消息}
}
2.2.2 兄弟組件通信
兄弟組件間通信較為復(fù)雜,通常通過(guò)它們的共同父組件來(lái)實(shí)現(xiàn)數(shù)據(jù)傳遞,或者使用服務(wù)(Service)來(lái)共享數(shù)據(jù)。
使用服務(wù)進(jìn)行兄弟組件通信的示例代碼:
// 共享服務(wù)Service.ts
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';@Injectable({providedIn: 'root'
})
export class SharedService {private messageSource = new Subject<string>();currentMessage = this.messageSource.asObservable();changeMessage(message: string) {this.messageSource.next(message);}
}
// 兄弟組件1 BrotherComponent1.ts
import { Component } from '@angular/core';
import { SharedService } from './service';@Component({selector: 'app-brother-1',template: `<button (click)="changeMessage()">Send Message</button>`
})
export class BrotherComponent1 {constructor(private sharedService: SharedService) {}changeMessage() {this.sharedService.changeMessage('Message from brother 1');}
}
// 兄弟組件2 BrotherComponent2.ts
import { Component, OnInit } from '@angular/core';
import { SharedService } from './service';@Component({selector: 'app-brother-2',template: `<p>Received: {{ message }}</p>`
})
export class BrotherComponent2 implements OnInit {message: string;constructor(private sharedService: SharedService) {}ngOnInit() {this.sharedService.currentMessage.subscribe(message => this.message = message);}
}
2.2.3 服務(wù)和狀態(tài)管理
在Angular應(yīng)用中,服務(wù)(Service)是用來(lái)實(shí)現(xiàn)業(yè)務(wù)邏輯或數(shù)據(jù)共享的單例對(duì)象。服務(wù)可以用來(lái)跨組件共享數(shù)據(jù)或方法,也可以用于實(shí)現(xiàn)復(fù)雜的狀態(tài)管理。
使用服務(wù)來(lái)管理組件狀態(tài)的示例代碼:
// 計(jì)數(shù)器服務(wù)CounterService.ts
import { Injectable } from '@angular/core';@Injectable({providedIn: 'root'
})
export class CounterService {private count = 0;getCount() {return this.count;}increase() {this.count++;}
}
// 組件CounterComponent.ts
import { Component } from '@angular/core';
import { CounterService } from './counter.service';@Component({selector: 'app-counter',template: `<button (click)="increase()">Increase</button><p>Count: {{ count }}</p>`
})
export class CounterComponent {count: number;constructor(private counterService: CounterService) {this.count = counterService.getCount();}increase() {this.counterService.increase();this.count = this.counterService.getCount();}
}
2.3 模塊化組織代碼
2.3.1 NgModules的作用與結(jié)構(gòu)
Angular模塊(Angular Modules,簡(jiǎn)稱NgModules)是組織組件、指令和服務(wù)的一種方式。每個(gè)Angular應(yīng)用至少包含一個(gè)根模塊,通常命名為 AppModule
。NgModules的結(jié)構(gòu)如下:
- 聲明數(shù)組 :列出了組件、指令和管道等類。
- 導(dǎo)入數(shù)組 :引入了所需的其他模塊。
- 導(dǎo)出數(shù)組 :聲明了模塊對(duì)外暴露的公共組件、指令和管道。
- 提供者數(shù)組 :用于配置服務(wù)提供者。
2.3.2 特性模塊與共享模塊
特性模塊(Feature Modules)和共享模塊(Shared Modules)是NgModules的兩種常見用法。
- 特性模塊 :將應(yīng)用的一個(gè)功能區(qū)域劃分為一個(gè)獨(dú)立的模塊,例如,購(gòu)物車模塊、用戶管理模塊。
- 共享模塊 :將那些被多個(gè)模塊共享的組件、指令和管道統(tǒng)一組織到一個(gè)模塊中。
2.3.3 模塊懶加載與性能提升
模塊懶加載是一種優(yōu)化技術(shù),可以延遲加載應(yīng)用中的某些模塊,僅在需要時(shí)才加載這些模塊。這有助于減少初始加載時(shí)間,提升應(yīng)用性能。
要實(shí)現(xiàn)模塊懶加載,可以使用Angular CLI命令生成一個(gè)新的特性模塊,并在路由配置中使用 loadChildren
來(lái)指定懶加載的模塊路徑。
示例代碼:
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';const routes: Routes = [{ path: '', redirectTo: '/home', pathMatch: 'full' },{ path: 'home', component: HomeComponent },{ path: 'lazy', loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule) }
];@NgModule({imports: [RouterModule.forRoot(routes)],exports: [RouterModule]
})
export class AppRoutingModule { }
以上是對(duì)Angular組件化開發(fā)和組織的二級(jí)章節(jié)內(nèi)容的詳細(xì)介紹,覆蓋了組件化基礎(chǔ)概念、組件間通信機(jī)制以及模塊化組織代碼的各個(gè)方面。這些章節(jié)內(nèi)容為深入理解和應(yīng)用Angular的組件化開發(fā)提供了堅(jiān)實(shí)的基礎(chǔ)。
3. 依賴注入(DI)實(shí)踐
依賴注入(Dependency Injection, DI)是Angular框架的核心概念之一,它允許開發(fā)者將組件與服務(wù)(或其它依賴)的耦合度降低,從而提高代碼的模塊化和可測(cè)試性。通過(guò)DI,Angular在運(yùn)行時(shí)負(fù)責(zé)解析組件、指令和管道所需的所有依賴項(xiàng),并在創(chuàng)建時(shí)將它們注入。
3.1 依賴注入的原理
3.1.1 依賴注入系統(tǒng)概述
在Angular中,依賴注入系統(tǒng)涉及三個(gè)主要概念:Token、Provider和Injector。
- Token:標(biāo)識(shí)依賴項(xiàng)的標(biāo)識(shí)符,通常是一個(gè)類或一個(gè)字符串。
- Provider:提供依賴項(xiàng)實(shí)例的配方或藍(lán)圖,可以是一個(gè)類、一個(gè)值,或者一個(gè)工廠函數(shù)。
- Injector:管理依賴項(xiàng)的注冊(cè)和解析的容器。Injector根據(jù)Token查找Provider,并創(chuàng)建或獲取依賴項(xiàng)實(shí)例。
依賴項(xiàng)的實(shí)例在首次請(qǐng)求時(shí)創(chuàng)建,并被緩存以供后續(xù)請(qǐng)求使用。這個(gè)緩存機(jī)制可以顯著提高應(yīng)用的性能。
3.1.2 依賴提供者和注入令牌
每個(gè)依賴項(xiàng)都需要一個(gè)Provider來(lái)定義如何創(chuàng)建或獲取它的實(shí)例。注入令牌(Token)是提供者的唯一標(biāo)識(shí)符。在Angular中,可以使用類本身作為Token,也可以創(chuàng)建自定義Token。
// 自定義Token示例
import { InjectionToken } from '@angular/core';export const APP_CONFIG = new InjectionToken<AppConfig>('app.config');// 在模塊中提供依賴項(xiàng)
providers: [{ provide: APP_CONFIG, useValue: { apiEndpoint: 'http://localhost:3000' } },
]
在上面的代碼塊中,我們定義了一個(gè)名為 APP_CONFIG
的自定義Token,并在模塊的 providers
數(shù)組中通過(guò) { provide, useValue }
的方式提供了一個(gè)配置對(duì)象。這個(gè)配置對(duì)象隨后可以在需要的地方通過(guò) @Inject(APP_CONFIG)
注入。
3.2 注入策略和裝飾器
3.2.1 常用的注入修飾符
Angular提供了幾個(gè)裝飾器用于控制依賴注入的策略:
-
@Inject()
:用于明確指定注入的Token。 -
@Optional()
:表示注入的依賴項(xiàng)是可選的,如果沒(méi)有提供,則注入undefined
。 -
@Self()
:限制依賴查找范圍為當(dāng)前組件或指令本身,不會(huì)向上查找父級(jí) injector。 -
@SkipSelf()
:與@Self()
相反,跳過(guò)當(dāng)前 injector,向上查找父級(jí) injector。
3.2.2 自定義提供者和多提供者
開發(fā)者可以提供自定義的依賴項(xiàng),或者為同一個(gè)Token提供多個(gè)提供者,Angular將會(huì)根據(jù)依賴的類型自動(dòng)選擇合適的提供者。
// 自定義提供者示例
providers: [{ provide: SomeService, useClass: RealSomeService },{ provide: SomeService, useClass: MockSomeService, deps: [LoggerService] },{ provide: SomeService, useFactory: (dep1, dep2) => new SomeService(dep1, dep2), deps: [Dep1, Dep2] },
]
在上述代碼中,我們?yōu)? SomeService
提供了三種不同的提供者,具體使用哪個(gè)提供者取決于依賴項(xiàng)的解析過(guò)程。
3.3 實(shí)戰(zhàn)依賴注入案例
3.3.1 實(shí)現(xiàn)服務(wù)的依賴注入
假設(shè)我們有一個(gè) LoggerService
用于記錄日志,我們想在 UserService
中使用它。
// UserService.ts
import { Injectable } from '@angular/core';
import { LoggerService } from './logger.service';@Injectable({ providedIn: 'root' })
export class UserService {constructor(private logger: LoggerService) { }createUser(user: User): void {this.logger.log('User created: ' + user.name);// ...create user logic}
}
在 UserService
中,我們使用 @Injectable()
裝飾器聲明該服務(wù),并通過(guò)構(gòu)造函數(shù)注入 LoggerService
。
3.3.2 配置注入和測(cè)試
在配置依賴注入時(shí),確保提供者的范圍和生命周期符合應(yīng)用需求。而在測(cè)試中,可以利用Angular的測(cè)試工具包中的 TestBed
來(lái)模擬依賴注入環(huán)境。
// UserService.spec.ts
import { TestBed } from '@angular/core/testing';describe('UserService', () => {let userService: UserService;beforeEach(() => {TestBed.configureTestingModule({providers: [UserService,LoggerService]});userService = TestBed.inject(UserService);});it('should be created', () => {expect(userService).toBeTruthy();});
});
在測(cè)試用例中,我們通過(guò)配置 TestBed
來(lái)提供需要測(cè)試的 UserService
以及它依賴的 LoggerService
。通過(guò)這種方式,我們可以對(duì) UserService
進(jìn)行隔離測(cè)試。
依賴注入是Angular中一項(xiàng)強(qiáng)大的功能,通過(guò)合理地使用依賴注入系統(tǒng),開發(fā)者可以編寫更加模塊化、易于維護(hù)和測(cè)試的代碼。
4. 數(shù)據(jù)綁定技術(shù)與雙向綁定
在現(xiàn)代的前端框架中,數(shù)據(jù)綁定是連接視圖和模型的橋梁,確保了當(dāng)數(shù)據(jù)源發(fā)生變化時(shí),用戶界面可以即時(shí)做出響應(yīng)。Angular 作為一款成熟的前端框架,其數(shù)據(jù)綁定和雙向綁定技術(shù)是其核心特性之一。開發(fā)者可以利用這些特性,快速構(gòu)建動(dòng)態(tài)且響應(yīng)式的用戶界面。
4.1 數(shù)據(jù)綁定基礎(chǔ)
數(shù)據(jù)綁定是將視圖層(HTML模板)和數(shù)據(jù)模型層進(jìn)行連接的過(guò)程,使得模板中的數(shù)據(jù)可以反映數(shù)據(jù)模型的狀態(tài)變化。Angular 提供了豐富的數(shù)據(jù)綁定選項(xiàng),包括屬性綁定和事件綁定。
4.1.1 屬性綁定和事件綁定
在Angular中,屬性綁定是一種單向的數(shù)據(jù)流,即數(shù)據(jù)從組件類流向模板視圖。通過(guò)使用方括號(hào) [ ]
,開發(fā)者可以將組件的屬性綁定到模板中的DOM屬性上。
<!-- 屬性綁定的簡(jiǎn)單示例 -->
<img [src]="item.image" (click)="toggleImage(item.id)">
在上述代碼中, item.image
是一個(gè)組件類屬性,通過(guò)屬性綁定顯示在 img
標(biāo)簽的 src
屬性中。而 (click)
是事件綁定,當(dāng)用戶點(diǎn)擊圖片時(shí),會(huì)觸發(fā) toggleImage(item.id)
方法。
事件綁定則相反,它允許模板向組件類發(fā)送消息。在Angular中,事件綁定使用圓括號(hào) ()
來(lái)標(biāo)識(shí)。例如,可以綁定一個(gè)點(diǎn)擊事件到一個(gè)按鈕上:
// 事件綁定的組件類方法示例
toggleImage(imageId: number) {// 點(diǎn)擊事件處理邏輯console.log(`Image with ID ${imageId} clicked`);
}
4.1.2 雙向數(shù)據(jù)綁定的實(shí)現(xiàn)
雙向數(shù)據(jù)綁定是通過(guò)Angular的 [(ngModel)]
指令實(shí)現(xiàn)的,它將一個(gè)HTML表單元素的值與組件類的屬性進(jìn)行雙向綁定。這意味著當(dāng)模板中的表單元素值改變時(shí),組件類的屬性會(huì)相應(yīng)地更新,反之亦然。
<!-- 雙向數(shù)據(jù)綁定的簡(jiǎn)單示例 -->
<input type="text" [(ngModel)]="user.name">
在上述代碼中,當(dāng)用戶在文本框中輸入數(shù)據(jù)時(shí), user.name
組件類的屬性會(huì)自動(dòng)更新。同時(shí),如果 user.name
的值在組件中被更新,文本框中的內(nèi)容也會(huì)相應(yīng)改變。
4.2 數(shù)據(jù)流和變更檢測(cè)
在數(shù)據(jù)綁定中,變更檢測(cè)是關(guān)鍵的一環(huán)。它負(fù)責(zé)在數(shù)據(jù)變更時(shí)更新視圖,使得視圖能夠反映最新的數(shù)據(jù)狀態(tài)。
4.2.1 變更檢測(cè)機(jī)制原理
Angular的變更檢測(cè)機(jī)制是一個(gè)周期性的過(guò)程,它從根組件開始,遞歸地遍歷組件樹來(lái)檢查數(shù)據(jù)的變化。在每次變更檢測(cè)過(guò)程中,Angular都會(huì)比較視圖和模型的狀態(tài),并且將變更同步到視圖上。
4.2.2 如何控制變更檢測(cè)流程
開發(fā)者可以手動(dòng)觸發(fā)變更檢測(cè),也可以使用 ChangeDetectorRef
來(lái)控制變更檢測(cè)的策略。在某些情況下,如性能優(yōu)化,開發(fā)者可能希望手動(dòng)控制變更檢測(cè)的觸發(fā)。
import { ChangeDetectorRef } from '@angular/core';constructor(private cdRef: ChangeDetectorRef) {}someMethod() {// 執(zhí)行一些操作導(dǎo)致數(shù)據(jù)變化// 顯式觸發(fā)變更檢測(cè)this.cdRef.detectChanges();
}
4.3 實(shí)踐中的數(shù)據(jù)綁定應(yīng)用
數(shù)據(jù)綁定技術(shù)在實(shí)際開發(fā)中有著廣泛的應(yīng)用。在本節(jié)中,我們將通過(guò)幾個(gè)實(shí)踐案例進(jìn)一步了解數(shù)據(jù)綁定如何應(yīng)用于實(shí)際開發(fā)。
4.3.1 表單數(shù)據(jù)綁定實(shí)例
表單是數(shù)據(jù)綁定的一個(gè)典型應(yīng)用場(chǎng)景。使用Angular的 [(ngModel)]
可以實(shí)現(xiàn)復(fù)雜表單的雙向數(shù)據(jù)綁定,極大簡(jiǎn)化了表單驗(yàn)證和數(shù)據(jù)同步的工作。
<!-- 表單數(shù)據(jù)綁定示例 -->
<form (ngSubmit)="onSubmit()"><input type="text" [(ngModel)]="formModel.name" name="name"><input type="email" [(ngModel)]="formModel.email" name="email"><button type="submit">Submit</button>
</form>
在上述示例中,表單的輸入字段與 formModel
組件類屬性進(jìn)行了雙向綁定,當(dāng)表單提交時(shí),可以獲取到最新的用戶輸入數(shù)據(jù)。
4.3.2 動(dòng)態(tài)模板和內(nèi)容投影
動(dòng)態(tài)模板和內(nèi)容投影是Angular模板高級(jí)功能的一部分,可以將組件的內(nèi)容投影到另一個(gè)組件中,或根據(jù)條件動(dòng)態(tài)地選擇模板。這對(duì)于構(gòu)建可復(fù)用的組件和復(fù)雜的用戶界面非常有用。
// 使用ngTemplateOutlet指令動(dòng)態(tài)投影內(nèi)容
<div *ngIf="showDynamicTemplate"><ng-container *ngTemplateOutlet="customTemplate"></ng-container>
</div><ng-template #customTemplate><p>Dynamic content</p>
</ng-template>
在上述代碼中, *ngIf
用于控制是否顯示動(dòng)態(tài)模板,而 *ngTemplateOutlet
用于插入預(yù)定義的模板。
通過(guò)本章節(jié)的介紹,我們了解了Angular中數(shù)據(jù)綁定技術(shù)的基礎(chǔ)和應(yīng)用。數(shù)據(jù)綁定不僅提供了視圖與數(shù)據(jù)交互的機(jī)制,也是構(gòu)建響應(yīng)式用戶界面不可或缺的一部分。在下一章中,我們將探索Angular中的依賴注入,這又是一個(gè)強(qiáng)大的特性,它為組件提供了強(qiáng)大的依賴解析和生命周期管理能力。
5. Angular路由配置與性能優(yōu)化
5.1 路由的基本使用
5.1.1 路由模塊和路由定義
Angular 路由模塊是用于頁(yè)面間導(dǎo)航的機(jī)制。它允許我們?cè)趩雾?yè)應(yīng)用(SPA)中定義多個(gè)視圖,并通過(guò) URL 控制它們的顯示與隱藏。路由模塊的導(dǎo)入對(duì)于設(shè)置路由至關(guān)重要。
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';const routes: Routes = [{ path: '', redirectTo: '/home', pathMatch: 'full' },{ path: 'home', component: HomeComponent },{ path: 'about', component: AboutComponent }
];@NgModule({imports: [RouterModule.forRoot(routes)],exports: [RouterModule]
})
export class AppRoutingModule { }
上述代碼定義了三個(gè)路由:主頁(yè)(重定向到 /home
)、 home
和 about
。使用 @NgModule
裝飾器配置路由模塊,并通過(guò) RouterModule.forRoot
方法進(jìn)行初始化,然后導(dǎo)出 RouterModule
以便可以在應(yīng)用的其它地方使用。
5.1.2 路由參數(shù)和守衛(wèi)
路由參數(shù)是 URL 中動(dòng)態(tài)部分,允許在不同組件間傳遞信息。通過(guò)在路由定義中添加冒號(hào) :
后跟參數(shù)名來(lái)定義它們:
{ path: 'user/:id', component: UserComponent }
路由守衛(wèi)則用于控制訪問(wèn)權(quán)限,它們返回一個(gè)布爾值或者一個(gè)Observable來(lái)確定是否可以激活路由或者繼續(xù)導(dǎo)航。例如,檢查用戶是否登錄:
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';@Injectable({providedIn: 'root'
})
export class AuthGuard implements CanActivate {canActivate(next: ActivatedRouteSnapshot,state: RouterStateSnapshot): Observable<boolean>|Promise<boolean>|boolean {const user = getUser();if (user && user.authenticated) {return true;}// 用戶未認(rèn)證時(shí)重定向到登錄頁(yè)面this.router.navigate(['/login']);return false;}
}
該 AuthGuard
類實(shí)現(xiàn)了 CanActivate
接口,用于驗(yàn)證用戶狀態(tài)。如果用戶未認(rèn)證,則將重定向到登錄頁(yè)面。
5.2 路由高級(jí)特性
5.2.1 嵌套路由和路由加載策略
嵌套路由允許我們?cè)诟附M件中設(shè)置子路由,這對(duì)于構(gòu)建具有復(fù)雜視圖層次結(jié)構(gòu)的應(yīng)用非常有用。在父組件的模板中,我們使用 <router-outlet>
指令來(lái)指示子路由內(nèi)容的展示位置。
<!-- app.component.html -->
<router-outlet></router-outlet>
<router-outlet name="aux"></router-outlet>
在路由配置中,嵌套路由通過(guò)在路徑中使用 children
屬性來(lái)定義。
const routes: Routes = [{ path: '', redirectTo: '/home', pathMatch: 'full' },{path: 'home',component: HomeComponent,children: [{ path: 'welcome', component: WelcomeComponent }]}
];
在上面的代碼中, welcome
路由成為了 home
路由的子路由。
路由加載策略包括預(yù)加載和按需加載。預(yù)加載會(huì)提前加載必要的路由模塊,而按需加載則在訪問(wèn)相應(yīng)路由時(shí)才加載。使用按需加載可以減少應(yīng)用的初始加載時(shí)間。
const routes: Routes = [{path: 'about',component: AboutComponent,loadChildren: () => import('./about/about.module').then(m => m.AboutModule)}
];
5.2.2 路由守衛(wèi)和異步加載
路由守衛(wèi)不僅可以用來(lái)控制訪問(wèn)權(quán)限,還可以用來(lái)確保在導(dǎo)航前某些操作已完成,比如服務(wù)調(diào)用或數(shù)據(jù)加載。異步加載是通過(guò) loadChildren
屬性來(lái)實(shí)現(xiàn)的。
{ path: 'admin', component: AdminComponent, canActivate: [AuthGuard], resolve: { user: AdminResolver } }
在上面的例子中, AuthGuard
用于檢查用戶是否具有訪問(wèn) admin
路由的權(quán)限。 AdminResolver
是一個(gè)解析器服務(wù),用來(lái)在激活路由之前獲取必要的數(shù)據(jù)。
5.3 性能優(yōu)化技巧
5.3.1 懶加載模塊的優(yōu)化
懶加載是將應(yīng)用的代碼庫(kù)拆分成多個(gè)塊(稱為懶加載塊),然后按需加載這些塊的技術(shù)。這可以顯著減少應(yīng)用的初始加載時(shí)間。在Angular中,可以通過(guò) loadChildren
指令來(lái)實(shí)現(xiàn)懶加載。
{ path: 'lazy', loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule) }
這里, lazy
路由指向一個(gè)懶加載模塊 LazyModule
。當(dāng)用戶訪問(wèn)這個(gè)路由時(shí),Angular CLI 會(huì)自動(dòng)處理代碼拆分和按需加載。
5.3.2 變更檢測(cè)性能優(yōu)化
Angular 的變更檢測(cè)機(jī)制會(huì)在每次變更檢測(cè)周期中檢查應(yīng)用的所有組件。在大型應(yīng)用中,這可能會(huì)影響性能。為了優(yōu)化這一過(guò)程,我們可以采取以下措施:
- 使用
OnPush
變更檢測(cè)策略,這樣變更檢測(cè)器只會(huì)檢查使用了該策略的組件,而不是整個(gè)組件樹。 - 通過(guò)減少不必要的數(shù)據(jù)綁定來(lái)減少變更檢測(cè)器需要檢查的內(nèi)容。
- 使用
ChangeDetectorRef
手動(dòng)觸發(fā)變更檢測(cè)。
// 在組件類中
constructor(private cd: ChangeDetectorRef) {}someMethod() {this.cd.detectChanges(); // 手動(dòng)觸發(fā)變更檢測(cè)
}
通過(guò)上述方法,可以有效地控制變更檢測(cè)流程,減少不必要的檢測(cè),從而優(yōu)化性能。
通過(guò)這些章節(jié)的詳細(xì)介紹,您已經(jīng)了解了Angular路由的配置方法,包括基本使用、高級(jí)特性以及性能優(yōu)化技巧。希望本文檔可以幫助您更好地構(gòu)建和優(yōu)化Angular應(yīng)用的路由系統(tǒng)。
6. HTML與Angular模板語(yǔ)法
6.1 核心模板指令
6.1.1 NgIf、NgFor和NgSwitch
Angular模板指令是用于操作DOM和與用戶界面交互的基本工具。其中, NgIf
、 NgFor
和 NgSwitch
是三個(gè)最基礎(chǔ)且最重要的模板指令,它們可以幫助開發(fā)者在HTML中動(dòng)態(tài)地渲染數(shù)據(jù)。
-
NgIf
用于條件性地在DOM中添加或移除元素。當(dāng)條件表達(dá)式的結(jié)果為true
時(shí),元素會(huì)被插入到DOM中;反之,元素則被從DOM中移除。其好處是可以避免不必要的DOM操作和相關(guān)的計(jì)算,從而提高性能。
<!-- 當(dāng) `user` 對(duì)象存在時(shí)顯示,不存在時(shí)隱藏 -->
<div *ngIf="user; else noUser">Welcome, {{ user.name }}!</div>
<ng-template #noUser>No user found.</ng-template>
-
NgFor
用于遍歷列表,并為列表中的每個(gè)項(xiàng)目創(chuàng)建一組元素。它類似于JavaScript中的forEach
循環(huán),但直接作用于HTML模板中。
<!-- 顯示 `items` 列表中的每個(gè)項(xiàng)目 -->
<ul><li *ngFor="let item of items; index as i">{{ i + 1 }} - {{ item }}</li>
</ul>
-
NgSwitch
是一種多條件的切換指令,類似于JavaScript中的switch
語(yǔ)句。當(dāng)需要在多個(gè)模板之間基于條件進(jìn)行切換時(shí)非常有用。
<!-- 根據(jù) `selected` 的值切換顯示不同的內(nèi)容 -->
<div [ngSwitch]="selected"><p *ngSwitchCase="'first'">First choice</p><p *ngSwitchCase="'second'">Second choice</p><p *ngSwitchDefault>Last choice</p>
</div>
6.1.2 輸入(@Input)和輸出(@Output)屬性
Angular組件之間的通信經(jīng)常需要通過(guò)屬性綁定實(shí)現(xiàn),而 @Input
和 @Output
裝飾器正是用于這個(gè)目的。
-
@Input
用于聲明一個(gè)屬性,允許外部數(shù)據(jù)通過(guò)屬性綁定的方式流入組件。
// 子組件
@Input() user: User;
<!-- 父組件模板中使用子組件 -->
<app-child [user]="parentUser"></app-child>
-
@Output
用于聲明一個(gè)事件發(fā)射器,允許組件將事件發(fā)送到父組件。通常,它與Angular的事件綁定語(yǔ)法((event)
)結(jié)合使用。
// 子組件
@Output() userChange = new EventEmitter<User>();// 當(dāng)用戶信息變化時(shí)觸發(fā)事件
updateUser() {this.userChange.emit(this.user);
}
<!-- 父組件模板中監(jiān)聽事件 -->
<app-child (userChange)="onUserChange($event)"></app-child>
6.2 管道的使用和自定義
6.2.1 內(nèi)建管道的使用場(chǎng)景
Angular提供了許多現(xiàn)成的管道(Pipe),這些管道可以應(yīng)用于模板中,以便對(duì)數(shù)據(jù)進(jìn)行轉(zhuǎn)換。例如, DatePipe
可以格式化日期, UpperCasePipe
可以將文本轉(zhuǎn)換為大寫。
<!-- 將時(shí)間戳轉(zhuǎn)換為日期格式 -->
<p>The current date is {{ today | date:'short' }}.</p><!-- 將字符串轉(zhuǎn)換為大寫 -->
<p>Convert to uppercase: {{ 'hello' | uppercase }}</p>
使用內(nèi)建管道可以節(jié)省大量的數(shù)據(jù)處理代碼,并且使模板更加簡(jiǎn)潔。
6.2.2 創(chuàng)建自定義管道
當(dāng)內(nèi)建管道無(wú)法滿足需求時(shí),我們可以創(chuàng)建自定義管道。自定義管道可以對(duì)輸入的值進(jìn)行轉(zhuǎn)換并返回一個(gè)新的值。下面是一個(gè)簡(jiǎn)單的自定義管道示例,用于格式化貨幣值:
import { Pipe, PipeTransform } from '@angular/core';@Pipe({name: 'currency'
})
export class CurrencyPipe implements PipeTransform {transform(value: number, currencyCode: string = 'USD'): string {return '$' + value.toFixed(2);}
}
<!-- 在模板中使用自定義管道 -->
<p>Price: {{ 1234 | currency }}</p>
創(chuàng)建自定義管道是一個(gè)強(qiáng)大而靈活的方式來(lái)定制數(shù)據(jù)展示,使得我們的應(yīng)用程序更加靈活且可重用。
6.3 模板語(yǔ)法高級(jí)技巧
6.3.1 模板引用變量和模板輸入變量
模板引用變量允許我們?cè)谀0鍍?nèi)部引用DOM元素或指令,而模板輸入變量用于在 NgFor
指令中定義迭代項(xiàng)的變量。
<!-- 引用DOM元素 -->
<input #myInput><!-- 點(diǎn)擊按鈕將獲取輸入框的值 -->
<button (click)="getValue(myInput.value)">Get Value</button>
<!-- 在NgFor中使用模板輸入變量 -->
<ul><li *ngFor="let item of items; let i = index">{{ i }} - {{ item }}</li>
</ul>
模板引用變量和輸入變量為模板提供了更多的控制和靈活性,使得我們能夠?qū)崿F(xiàn)更復(fù)雜的交互邏輯。
6.3.2 視圖封裝和樣式綁定
視圖封裝是指Angular組件的CSS樣式僅限于組件本身,不會(huì)影響到其他組件。這是通過(guò)在組件的元數(shù)據(jù)中設(shè)置 encapsulation
屬性實(shí)現(xiàn)的,主要有三個(gè)選項(xiàng): ViewEncapsulation.None
、 ViewEncapsulation.Emulated
和 ViewEncapsulation.ShadowDom
。
@Component({// ...encapsulation: ViewEncapsulation.Emulated // 默認(rèn)值
})
樣式綁定允許我們?cè)谀0逯袆?dòng)態(tài)地應(yīng)用樣式類和內(nèi)聯(lián)樣式。我們可以根據(jù)條件來(lái)添加或移除樣式類,也可以直接綁定樣式屬性。
<!-- 根據(jù)條件動(dòng)態(tài)添加樣式類 -->
<div [class.active]="isActive">Item</div><!-- 綁定內(nèi)聯(lián)樣式 -->
<div [style.background-color]="isActive ? 'green' : 'transparent'">Item</div>
視圖封裝和樣式綁定使得樣式管理更為靈活,組件的樣式不再相互沖突,從而提高了開發(fā)的效率和組件的可重用性。
通過(guò)掌握Angular模板語(yǔ)法的核心指令、管道的使用、以及高級(jí)技巧,開發(fā)者可以編寫更加動(dòng)態(tài)、響應(yīng)式的用戶界面,并能夠創(chuàng)建更加模塊化和可維護(hù)的應(yīng)用程序。隨著對(duì)模板語(yǔ)法深入理解的增強(qiáng),你可以更加自信地構(gòu)建復(fù)雜的應(yīng)用,并在必要時(shí)通過(guò)自定義管道和指令擴(kuò)展模板的功能。
7. 新特性:CLI改進(jìn)、RxJS 6.6和Ivy編譯器
Angular持續(xù)推動(dòng)開發(fā)者的生產(chǎn)力,提供更快的編譯速度,更清晰的命令行接口(CLI)功能,并與RxJS緊密結(jié)合,提供更為強(qiáng)大的響應(yīng)式編程支持。Ivy編譯器作為Angular的下一代編譯器,為構(gòu)建時(shí)和運(yùn)行時(shí)性能帶來(lái)了顯著的提升。
7.1 Angular CLI的更新和改進(jìn)
自Angular 6起,Angular CLI引入了Schematics,為項(xiàng)目的初始化、修改和擴(kuò)展提供了模板化的解決方案。在Angular 11中,CLI的更新集中在簡(jiǎn)化項(xiàng)目創(chuàng)建和工作流程,以及項(xiàng)目配置的優(yōu)化。
7.1.1 新的命令和工作流程
CLI的命令行工具在Angular 11中新增了幾個(gè)方便用戶操作的功能,例如 ng update
,此命令可幫助開發(fā)者自動(dòng)識(shí)別并升級(jí)項(xiàng)目中的依賴項(xiàng),為遷移至新版本提供便利。另一個(gè)新增功能是 ng test
命令現(xiàn)在可以支持Jest測(cè)試框架,提供更多的測(cè)試選項(xiàng)。
ng update @angular/cli
ng test --watch=false
7.1.2 項(xiàng)目的配置和優(yōu)化
Angular 11中,CLI允許更靈活的項(xiàng)目配置,通過(guò) angular.json
文件可以對(duì)構(gòu)建和開發(fā)服務(wù)器的選項(xiàng)進(jìn)行定制。此外,新增了對(duì)文件大小報(bào)告的支持,能夠生成一個(gè)概覽文件,方便開發(fā)者分析和優(yōu)化應(yīng)用的大小。
7.2 RxJS 6.6的新特性
RxJS作為Angular中的響應(yīng)式編程庫(kù),在6.6版本中引入了新的操作符,使得數(shù)據(jù)處理更為直觀和簡(jiǎn)潔。
7.2.1 操作符的變更和新特性
RxJS 6.6引入了幾個(gè)新的操作符,如 tap
, startWith
, expand
等,同時(shí)也對(duì)一些操作符進(jìn)行了命名上的調(diào)整。例如, flatMap
現(xiàn)在被稱為 mergeMap
,這些變更有助于減少對(duì)操作符功能的誤解,提供更清晰的API。
import { fromEvent } from 'rxjs';
import { mergeMap, tap } from 'rxjs/operators';const clicks = fromEvent(document, 'click');
const sum = clicks.pipe(mergeMap(() => of(1, 2, 3)),tap(x => console.log(x))
);
sum.subscribe(x => console.log(x));
7.2.2 響應(yīng)式編程在Angular中的應(yīng)用
響應(yīng)式編程在Angular中的應(yīng)用可以極大地簡(jiǎn)化異步數(shù)據(jù)流的管理,通過(guò)RxJS的強(qiáng)大功能,開發(fā)者可以輕松地創(chuàng)建復(fù)雜的異步邏輯。RxJS與Angular的結(jié)合,特別是在使用 HttpClient
時(shí),可以創(chuàng)建可組合、易于維護(hù)的API請(qǐng)求邏輯。
7.3 Ivy編譯器的變革
Ivy編譯器的引入是Angular 9的一個(gè)重要里程碑,到了Angular 11,Ivy已經(jīng)成為了默認(rèn)的編譯器和運(yùn)行時(shí)。
7.3.1 Ivy編譯器的工作原理
Ivy編譯器優(yōu)化了應(yīng)用的構(gòu)建過(guò)程,它能夠生成更小、更快的代碼,并且能夠更精確地進(jìn)行增量編譯,從而加快開發(fā)速度。Ivy通過(guò)將組件和指令的模板直接編譯進(jìn)JavaScript代碼,減少了運(yùn)行時(shí)的解析負(fù)擔(dān)。
7.3.2 對(duì)項(xiàng)目構(gòu)建和運(yùn)行時(shí)性能的影響
Ivy的引入大幅提升了應(yīng)用的運(yùn)行時(shí)性能,尤其是在首屏加載速度上。因?yàn)镮vy編譯器能夠更加智能地分析和利用應(yīng)用中的共享模塊,減少了重復(fù)代碼,從而優(yōu)化了最終的構(gòu)建產(chǎn)物。同時(shí),Ivy支持了更為細(xì)粒度的變化檢測(cè),進(jìn)一步提升了應(yīng)用性能。
通過(guò)這些新特性的探討,我們可以看到Angular在持續(xù)進(jìn)化中為開發(fā)者提供更好的開發(fā)體驗(yàn)和性能優(yōu)化。無(wú)論是CLI工具的改進(jìn),RxJS的增強(qiáng),還是Ivy編譯器的引入,都體現(xiàn)了Angular不斷適應(yīng)開發(fā)需求和保持技術(shù)先進(jìn)的決心。
本文還有配套的精品資源,點(diǎn)擊獲取
簡(jiǎn)介:Angular 11是Google支持的前端框架,適合構(gòu)建復(fù)雜的單頁(yè)應(yīng)用(SPA)。本課程將深入介紹Angular核心特性,如組件化、依賴注入、數(shù)據(jù)綁定和路由,并且涵蓋Angular 11的新特性,例如CLI改進(jìn)、RxJS 6.6和Ivy編譯器。通過(guò)實(shí)踐項(xiàng)目,學(xué)生將學(xué)會(huì)如何操作源碼文件、模板和樣式文件,進(jìn)而熟練掌握Angular開發(fā)。
本文還有配套的精品資源,點(diǎn)擊獲取