這個架構圖展現了 Angular 應用中的 8 個主要構造塊:
- 模塊 (module)
- 組件 (component)
- 模板 (template)
- 元數據 (metadata)
- 數據綁定 (data binding)
- 指令 (directive)
- 管道
- 服務 (service)和依賴注入 (dependency injection)
圖中的模板 (Templates)是由 Angular 擴展的 HTML 語法組成,組件 (Components)類用來管理這些模板,應用邏輯部分通過服務 (Services)來完成,然后在模塊中打包服務與組件,最后通過引導根模塊來啟動應用。
模塊 (module)
模塊由一塊代碼組成,可用於執行一個簡單的任務。
Angular 應用是由模塊化的,它有自己的模塊系統:NgModules。
每個 Angular 應該至少要有一個模塊(根模塊),一般可以命名為:AppModule。
Angular 模塊是一個帶有 @NgModule 裝飾器的類,它接收一個用來描述模塊屬性的元數據對象。
@NgModule幾個重要的屬性如下:
-
imports:聲明本模塊引入的其它模塊。
-
providers:聲明本模塊引入的服務類。如果在根模塊中聲明,則它們在應用中的任何部分都可被訪問到。
-
declarations:聲明本模塊中擁有的視圖類。Angular 有三種視圖類:組件、指令和管道。
-
exports:聲明( declaration )的子集,可用於其它模塊中的組件模板 。
-
bootstrap 指定應用的主視圖(稱為根組件),它是所有其它視圖的宿主。只有根模塊才能設置 bootstrap 屬性。
//app.module.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; @NgModule({ imports: [ BrowserModule ], providers: [ Logger ], declarations: [ AppComponent ], exports: [ AppComponent ], bootstrap: [ AppComponent ] }) export class AppModule { }
一個最簡單的根模塊:
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; @NgModule({ imports: [ BrowserModule ], providers: [ Logger ], declarations: [ AppComponent ], exports: [ AppComponent ], bootstrap: [ AppComponent ] }) export class AppModule { }
接下來我們通過引導根模塊來啟動應用,開發過程通常在 main.ts 文件中來引導 AppModule ,代碼如下:
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app.module'; platformBrowserDynamic().bootstrapModule(AppModule);
組件 (component)
組件是一個模板的控制類用於處理應用和邏輯頁面的視圖部分。
組件是構成 Angular 應用的基礎和核心,可用於整個應用程序中。
組件知道如何渲染自己及配置依賴注入。
組件通過一些由屬性和方法組成的 API 與視圖交互。
創建 Angular 組件的方法有三步:
- 從 @angular/core 中引入 Component 修飾器
- 建立一個普通的類,並用 @Component 修飾它
- 在 @Component 中,設置 selector 自定義標簽,以及 template 模板
模板 (template)
Angular模板的默認語言就是HTML。
我們可以通過使用模板來定義組件的視圖來告訴 Angular 如何顯示組件。以下是一個簡單是實例:
<div> 網站地址 : {{site}} </div>
在Angular中,默認使用的是雙大括號作為插值語法,大括號中間的值通常是一個組件屬性的變量名。
元數據 (metadata)
元數據告訴 Angular 如何處理一個類。
考慮以下情況我們有一個組件叫作 Component ,它是一個類,直到我們告訴 Angular 這是一個組件為止。
你可以把元數據附加到這個類上來告訴 Angular Component 是一個組件。
在 TypeScript 中,我們用 裝飾器 (decorator) 來附加元數據。
實例
@Component({ selector : 'mylist', template : '<h2>菜鳥教程</h2>' directives : [ComponentDetails] }) export class ListComponent{...}
@Component 裝飾器能接受一個配置對象,並把緊隨其后的類標記成了組件類。
Angular 會基於這些信息創建和展示組件及其視圖。
@Component 中的配置項說明:
-
selector - 一個 css 選擇器,它告訴 Angular 在 父級 HTML 中尋找一個 <mylist> 標簽,然后創建該組件,並插入此標簽中。
-
templateUrl - 組件 HTML 模板的地址。或者直接寫html內容,用“`”括起來
-
directives - 一個數組,包含此模板需要依賴的組件或指令。
-
providers - 一個數組,包含組件所依賴的服務所需要的依賴注入提供者。
數據綁定 (data binding)
數據綁定為應用程序提供了一種簡單而一致的方法來顯示數據以及數據交互,它是管理應用程序里面數值的一種機制。
通過這種機制,可以從HTML里面取值和賦值,使得數據的讀寫,數據的持久化操作變得更加簡單快捷。
如圖所示,數據綁定的語法有四種形式。每種形式都有一個方向——從 DOM 來、到 DOM 去、雙向,就像圖中的箭頭所示意的。
代碼例子:
//插值表達式 在 HTML 標簽中顯示組件值。 <li>{{hero.name}}</li> //屬性綁定 把父組件HeroListComponent
的selectedHero
的值傳到子組件HeroDetailComponent
的hero
屬性中。 <hero-detail [hero]="selectedHero"></hero-detail> //事件綁定 用戶點擊英雄的名字時調用組件的selectHero方法。 <li (click)="selectHero(hero)"></li> //雙向綁定 數據屬性值通過屬性綁定從組件流到輸入框。用戶的修改通過事件綁定流回組件,把屬性值設置為最新的值。 <input [(ngModel)]="hero.name">
可能大家對各種括號看的眼花了,總結一下:
- 雙花括號是單向綁定,傳遞的是值。方向是
組件 -> 模板
。 - 方括號是單向綁定,傳遞的是屬性。方向是
組件 -> 模板
。 - 圓括號是事件綁定,處理
點擊等活動(action)
。方向是 模板-> 組件
。 - 方括號套圓括號是雙向綁定,方向是
組件 <-> 模板
。
指令 (directive)
Angular模板是動態的 。當 Angular 渲染它們時,它會根據指令對 DOM 進行修改。
指令是一個帶有"指令元數據"的類。在 TypeScript 中,要通過 @Directive 裝飾器把元數據附加到類上。
在Angular中包含以下三種類型的指令:
- 屬性指令:以元素的屬性形式來使用的指令。
- 結構指令:用來改變DOM樹的結構
- 組件:作為指令的一個重要子類,組件本質上可以看作是一個帶有模板的指令。
<li *ngFor="let site of sites"></li> <site-detail *ngIf="selectedSite"></site-detail>
*ngFor 告訴 Angular 為 sites 列表中的每個項生成一個 <li> 標簽。
*ngIf 表示只有在選擇的項存在時,才會包含 SiteDetail 組件。
管道
Angular 的管道可以讓你在模板中聲明顯示值的轉換邏輯。 帶有 @Pipe
裝飾器的類中會定義一個轉換函數,用來把輸入值轉換成供視圖顯示用的輸出值。
Angular 自帶了很多管道,比如 date 管道和 currency 管道,完整的列表參見 Pipes API 列表。你也可以自己定義一些新管道。
要在 HTML 模板中指定值的轉換方式,請使用 管道操作符 (|)。
{{interpolated_value | pipe_name}}
你可以把管道串聯起來,把一個管道函數的輸出送給另一個管道函數進行轉換。 管道還能接收一些參數,來控制它該如何進行轉換。比如,你可以把要使用的日期格式傳給 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>
服務 (service)
服務是一個廣義的概念,它包括應用所需的任何值、函數或特性。狹義的服務是一個明確定義了用途的類。它應該做一些具體的事,並做好。
Angular 把組件和服務區分開,以提高模塊性和復用性。
-
通過把組件中和視圖有關的功能與其他類型的處理分離開,你可以讓組件類更加精簡、高效。 理想情況下,組件的工作只管用戶體驗,而不用顧及其它。 它應該提供用於數據綁定的屬性和方法,以便作為視圖(由模板渲染)和應用邏輯(通常包含一些模型的概念)的中介者。
-
組件不應該定義任何諸如從服務器獲取數據、驗證用戶輸入或直接往控制台中寫日志等工作。 而要把這些任務委托給各種服務。通過把各種處理任務定義到可注入的服務類中,你可以讓它可以被任何組件使用。 通過在不同的環境中注入同一種服務的不同提供商,你還可以讓你的應用更具適應性。
Angular 不會強制遵循這些原則。它只會通過依賴注入讓你能更容易地將應用邏輯分解為服務,並讓這些服務可用於各個組件中。
依賴注入 (dependency injection)
依賴注入是提供類的新實例的一種方式,還負責處理類所需的全部依賴。大多數依賴都是服務。 Angular 使用依賴注入來提供新組件以及組件所需的服務。
比如我們要給某組件導入 HeroService 這個服務,看這段代碼:
constructor(private service: HeroService) {
...
}
當 Angular 創建組件時,會首先為組件所需的服務找一個注入器( Injector ) 。
注入器是一個維護服務實例的容器,存放着以前創建的實例。
如果容器中還沒有所請求的服務實例,注入器就會創建一個服務實例,並且添加到容器中,然后把這個服務返回給 Angular 。
當所有的服務都被解析完並返回時, Angular 會以這些服務為參數去調用組件的構造函數。 這就是依賴注入 。
我們必須先用注入器 injector 為 HeroService 注冊一個提供商 provider。意思就是我們必須在 providers 寫上才能用,看這段代碼:
@Component({
selector: 'hero-list',
templateUrl: './hero-list.component.html',
providers: [ HeroService ]
})