Angular學習(一)術語概念的理解
裝飾器(Decorator)
裝飾器是一種設計模式,其主要應用場景是動態的將多個責任附加到一個物件上
,這是一種比繼承更有彈性的面對物件設計方法,缺點是程式碼中會出現大量的小類。
Angular中定義了許多裝飾器,他們是用於修飾 JavaScript 類的函式,用來將各種功能零件裝飾在一個個類上
。具體的實現方式是把一些特定用途的元件以預定義的方式附加到類上,組合成一個擁有完整功能的模組,以便於 Angular 框架了解這些這些類的含義並知道如何呼叫它們。
模組(NgModule)
Angular中的模組本質上是存放一些內聚程式碼塊的容器
,一個模組相當於一個功能單元,它們分別專注於某個功能或者工作流程,比如登入註冊功能可以作為一個模組。Angular專案中所有模組會被組裝成一棵樹
AppModule
。Angular的模組和 JavaScript中的模組不同,但是有一定的互補性。
Angular中定義一個模組的方法是通過使用@NgModule
裝飾器裝飾一個類,@NgModule
裝飾器為一個模組聲明瞭編譯的環境,即其作用域由@NgModule
定義。例如,我們可以匯入一些由其它模組中匯出的功能,並匯出一些指定的功能供其它模組使用。
@NgModule
的一些屬性:
- declarations(可宣告物件表) —— 那些屬於本模組的零件(元件、指令、管道)。
- exports(匯出表) —— 那些能在其它模組中使用的零件(元件、指令、管道)。
- imports(匯入表) —— 那些匯出了本模組中需要使用的其它模組。
- providers —— 宣告的服務可以在本模組或者本元件中使用。
- bootstrap —— 它是應用的主檢視,是所有其它元件的根。只有根模組才應該設定。
// 一個使用者模組的例子,模組使用@NgModule裝飾
@NgModule({
declarations: [ UserMainComponent, WritePostComponent ],
exports: [UserMainComponent],
imports:[CommonModule,ReactiveFormsModule,SharedModule,PostSharedModule,RouterModule.forChild (userRoutes)],
providers: [PostTableService]
})
export class UserModule {}
元件(Component)
Angular中的檢視指的是最終顯示在瀏覽器上的整個頁面或頁面的一部分。一塊檢視由元件類和模板構成,即一個元件類+一個模板=一塊檢視
。一個元件通常是指元件類+模板
。一個元件可以作為標籤來嵌入到其他模板中,以此來形成一個有複雜層次的檢視結構。
Angular中定義一個元件類的方式是通過@Component
裝飾器修飾一個類,這個類包含了與模板互動所需的資料和邏輯。模板是一個通過@Component
裝飾器與模板類繫結的html檔案。
當Angular建立、更新、銷燬一些元件時。我們可以通過重寫生命週期鉤子方法的方式,來在每個特定的時機執行特定的業務邏輯。
常用的 @Component 配置選項:
- selector:是一個 CSS 選擇器,它會告訴 Angular,一旦在HTML模板中找到了這個選擇器對應的標籤,就建立並插入該元件的一個例項。例如,如果HTML中包含 ,Angular 就會在這些標籤中插入一個 HeroListComponent 例項的檢視。
- templateUrl:是該元件的HTML 模板檔案相對於這個元件類的地址引用。另外,還可以用 template 屬性的值來直接填入HTML 模板程式碼。
- providers 是當前元件所需要的服務的陣列。
@Component({
selector: 'app-hero-list',
templateUrl: './hero-list.component.html',
providers: [ HeroService ]
})
export class HeroListComponent implements OnInit {
}
模板語法
模板語法主要包括了:元件標籤、管道、指令、資料繫結
資料繫結
模板中可以使用資料繫結來實現元件類和模板之間資料的互動
,Angular可以在元件類和模板DOM之間雙向的進行資料傳輸。
<!-- 以下是資料繫結的四種形式 -->
<li>{{hero.name}}</li> <!-- 將元件類中的hero變數的name屬性的值,從元件傳入到模板中 -->
<!-- 下面這個是元件標籤,它在模板中嵌入其他元件,並呼叫了其他元件的selectedHero()方法獲得返回值傳給hero -->
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
<li (click)="selectHero(hero)"></li> <!-- 通過click點選事件,將hero屬性的值從模板傳到元件類的selectHero()方法中,並呼叫方法 -->
<input [(ngModel)]="hero.name"> <!-- 這個是雙向的資料繫結,資料可以在模板和元件類中雙向的流動 -->
管道
Angular裡的管道可以將 我們在類中定義的轉換邏輯用在模板中。帶有@Pipe 裝飾器並實現PipeTransform介面的類中會定義一個轉換函式,用來把輸入值轉換成供檢視顯示用的輸出值。
Angular 自帶了很多管道,比如 date 管道和 currency 管道,也可以定義一些新管道。在HTML 模板中使用管道時使用操作符 (|)。管道也可以串聯起來,把一個管道的輸出送給另一個管道進行轉換。 並且能接收一些引數,來控制它該如何進行轉換。
<!-- 把要使用的日期格式傳給 date 管道 -->
<!-- Default format: output 'Jun 15, 2015'-->
<p>Today is {{today | date}}</p>
<!-- fullDate format: output 'Monday, June 15, 2015'-->
<p>The date is {{today | date:'fullDate'}}</p>
<!-- shortTime format: output '9:43 AM'-->
<p>The time is {{today | date:'shortTime'}}</p>
指令(Directives)
Angular 的模板是動態的。當 Angular 渲染它們的時候,會根據指令對 DOM進行轉換。指令就是一個帶有 @Directive 裝飾器的類。
元件本質上是一種特殊的指令。除元件外,還有兩種指令:結構型指令和屬性型指令。和元件一樣,指令的元資料把指令類和一個 selector 關聯起來,selector 用來把該指令插入到 HTML 中。 在模板中,指令通常作為屬性出現在元素標籤上,可能僅僅作為名字出現,也可能作為賦值目標或繫結目標出現。
結構型指令
結構型指令通過新增、移除或替換 DOM 元素來修改佈局。 這個範例模板使用了兩個內建的結構型指令來為要渲染的檢視新增程式邏輯:
<!-- *ngFor 是一個迭代器,它要求 Angular 為 list 列表中的每個 item 渲染出一個 `<li>`標籤 -->
<li *ngFor="let item of list"></li>
<!-- *ngIf 是個條件語句,只有當選中的英雄存在時,它才會包含 HeroDetail 元件。 -->
<app-hero-detail *ngIf="selectedHero"></app-hero-detail>
屬性型指令
屬性型指令會修改現有元素的外觀或行為。 在模板中,它們看起來就像普通的 HTML 屬性一樣,因此得名“屬性型指令”。
ngModel 指令就是屬性型指令的一個例子,它實現了雙向資料繫結。 ngModel 修改現有元素(一般是 )的行為:設定其顯示屬性值,並響應 change 事件。
<input [(ngModel)]="hero.name">
Angular 還有很多預定義指令,它們或者修改佈局結構(比如 ngSwitch),或者修改 DOM 元素和元件的某些方面(比如 ngStyle 和 ngClass)。
服務與依賴注入
服務
Angular為了把元件和服務區分開,以提高模組性和複用性。對於與特定檢視無關並希望跨元件共享的資料或邏輯,可以建立服務類。使用@Injectable
裝飾器可以定義一個服務類。該裝飾器提供的元資料可以讓服務作為依賴被自動注入到需要的元件中。
其中元件一般只用於提供資料繫結的屬性和方法,作為檢視和業務邏輯的中介者。元件不應該包含任何諸如從伺服器獲取資料、驗證使用者輸入或直接往控制檯中寫日誌等工作。而要把這些任務委託給各種服務。通過把業務邏輯定義在可注入的服務類中的方式,可以讓任何元件使用某一種服務。
// 這是一個服務類的例子,用於把日誌記錄到瀏覽器的控制檯
@Injectable()
export class Logger {
log(msg: any) { console.log(msg); }
error(msg: any) { console.error(msg); }
warn(msg: any) { console.warn(msg); }
}
// 服務也可以依賴其它服務。
// 比如,下面的HeroService 就依賴於 Logger 服務,它還用 BackendService 來獲取英雄資料。
// BackendService 還可能再轉而依賴 HttpClient 服務來從伺服器非同步獲取英雄列表。
@Injectable()
export class HeroService {
private heroes: Hero[] = [];
constructor(
private backend: BackendService,
private logger: Logger) { }
getHeroes() {
this.backend.getAll(Hero).then( (heroes: Hero[]) => {
this.logger.log(`Fetched ${heroes.length} heroes.`);
this.heroes.push(...heroes); // fill cache
});
return this.heroes;
}
}
依賴注入(DI)
依賴注入是面向物件程式設計中的一種設計原則,是面對物件程式設計的一種解耦方式。它將建立物件例項的許可權交給了框架(控制反轉)。當 Angular 建立元件類的新例項時,它會通過檢視該元件類的建構函式,來決定該元件依賴哪些服務或其它依賴項。
// 比如 HeroListComponent 的建構函式中需要 HeroService
constructor(private service: HeroService) { }
當 Angular 發現某個元件依賴某個服務時,它會首先檢查應用中是否已經有了那個服務的例項。如果該服務例項還不存在就會建立該服務的例項,並把該服務例項的傳給構造方法。
// 註冊服務有三種方式
// 在服務類中註冊到應用全域性中,此時該服務是全域性單例的
@Injectable({
providedIn: 'root',
})
// 在 @NgModule 中註冊時,該服務的同一個例項將會對該 NgModule 中的所有元件可用
@NgModule({
providers: [
BackendService,
Logger
],
...
})
// 在 @Component 中註冊時,會為該元件的每一個新例項提供該服務的一個新例項
@Component({
selector: 'app-hero-list',
templateUrl: './hero-list.component.html',
providers: [ HeroService ]
})
路由
Angular 的 Router 模組可以讓我們定義在應用的各個檢視及其狀態之間導航時要使用的路徑。定義導航規則是通過URL關聯元件。Angular應用可以根據URL決定要顯示或隱藏哪些檢視或者對使用者的輸入做出響應。
其中,路由器會把類似 URL 的路徑對映到元件對應的檢視而不是頁面。當用戶執行一個動作時(比如點選連結),本應該在瀏覽器中載入一個新頁面,但是路由器攔截了瀏覽器的這個行為,並顯示或隱藏一個檢視層次結構。如果路由器需要的模組尚未載入,路由器可以根據配置按需惰性載入。