1.組件
組件負(fù)責(zé)控制屏幕上的一小塊區(qū)域琐鲁,我們稱之為視圖菠齿。
例如志膀,下列視圖都是由組件控制的:
- 帶有導(dǎo)航鏈接的應(yīng)用根組件蝙昙。
- 英雄列表。
- 英雄編輯器
我們在類中定義組件的應(yīng)用邏輯梧却,為視圖提供支持。 組件通過一些由屬性和方法組成的 API 與視圖交互败去。
例如放航,HeroListComponent有一個(gè)heroes屬性,它返回一個(gè)英雄數(shù)組圆裕,這個(gè)數(shù)組從一個(gè)服務(wù)獲得广鳍。 HeroListComponent還有一個(gè)selectHero()方法,當(dāng)用戶從列表中點(diǎn)選一個(gè)英雄時(shí)吓妆,就把它/她設(shè)置到selectedHero屬性赊时。
當(dāng)用戶在這個(gè)應(yīng)用中漫游時(shí), Angular 會創(chuàng)建行拢、更新和銷毀組件祖秒。 應(yīng)用可以通過生命周期鉤子在組件生命周期的各個(gè)時(shí)間點(diǎn)上插入自己的操作,例如上面聲明的ngOnInit()
。
2.模版
我們通過組件的自帶的模板來定義組件視圖竭缝。模板以 HTML 形式存在房维,告訴 Angular 如何渲染組件。
多數(shù)情況下抬纸,模板看起來很像標(biāo)準(zhǔn) HTML咙俩,當(dāng)然也有一點(diǎn)不同的地方。下面是HeroListComponent組件的一個(gè)模板:
模板除了可以使用像 h2和p
這樣的典型的 HTML 元素湿故,還能使用其它元素阿趁。 例如,像*ngFor{{hero.name}}坛猪、(click)脖阵、[hero]和<hero-detail>這樣的代碼使用了 Angular 的模板語法。
在模板的最后一行砚哆,<hero-detail>標(biāo)簽就是一個(gè)用來表示新組件HeroDetailComponent的自定義元素独撇。
HeroDetailComponent跟以前見到過的HeroListComponent是不同的組件。 HeroDetailComponent(代碼未顯示)用于展現(xiàn)一個(gè)特定英雄的情況躁锁,這個(gè)英雄是用戶從HeroListComponent列表中選擇的纷铣。 HeroDetailComponent是HeroListComponent的子組件。
注意到了嗎战转?<hero-detail>舒適地躺在原生 HTML 元素之間搜立。 自定義組件和原生 HTML 在同一布局中融合得天衣無縫。
3.元數(shù)據(jù)
元數(shù)據(jù)告訴 Angular 如何處理一個(gè)類槐秧。
回頭看看HeroListComponent就會明白:它只是一個(gè)類啄踊。 一點(diǎn)框架的痕跡也沒有,里面完全沒有出現(xiàn) "Angular" 的字樣刁标。
實(shí)際上颠通,HeroListComponent真的只是一個(gè)類。直到我們告訴 Angular 它是一個(gè)組件膀懈。
要告訴 Angular HeroListComponent是個(gè)組件顿锰,只要把元數(shù)據(jù)附加到這個(gè)類。
在TypeScript中启搂,我們用**裝飾器 (decorator) **來附加元數(shù)據(jù)硼控。 下面就是HeroListComponent的一些元數(shù)據(jù)。
這里看到@Component裝飾器胳赌,它把緊隨其后的類標(biāo)記成了組件類牢撼。
@Component裝飾器能接受一個(gè)配置對象, Angular 會基于這些信息創(chuàng)建和展示組件及其視圖疑苫。
@Component的配置項(xiàng)包括:
- selector: CSS 選擇器熏版,它告訴 Angular 在父級 HTML 中查找<hero-list>標(biāo)簽纷责,創(chuàng)建并插入該組件。 例如纳决,如果應(yīng)用的 HTML 包含<hero-list></hero-list>碰逸, Angular 就會把HeroListComponent的一個(gè)實(shí)例插入到這個(gè)標(biāo)簽中。
- templateUrl:組件 HTML 模板的模塊相對地址阔加,如前所示饵史。
- providers - 組件所需服務(wù)的依賴注入提供商數(shù)組。 這是在告訴 Angular:該組件的構(gòu)造函數(shù)需要一個(gè)HeroService服務(wù)胜榔,這樣組件就可以從服務(wù)中獲得英雄數(shù)據(jù)胳喷。
@Component里面的元數(shù)據(jù)會告訴 Angular 從哪里獲取你為組件指定的主要的構(gòu)建塊。
模板夭织、元數(shù)據(jù)和組件共同描繪出這個(gè)視圖吭露。
其它元數(shù)據(jù)裝飾器用類似的方式來指導(dǎo) Angular 的行為。 例如@Injectable尊惰、@Input和@Output等是一些最常用的裝飾器讲竿。
4.數(shù)據(jù)綁定
如果沒有框架,我們就得自己把數(shù)據(jù)值推送到 HTML 控件中弄屡,并把用戶的反饋轉(zhuǎn)換成動(dòng)作和值更新题禀。 如果手工寫代碼來實(shí)現(xiàn)這些推/拉邏輯,肯定會枯燥乏味膀捷、容易出錯(cuò)迈嘹,讀起來簡直是噩夢 —— 寫過 jQuery 的程序員大概都對此深有體會。
Angular 支持?jǐn)?shù)據(jù)綁定全庸,一種讓模板的各部分與組件的各部分相互合作的機(jī)制秀仲。 我們往模板 HTML 中添加綁定標(biāo)記,來告訴 Angular 如何把二者聯(lián)系起來壶笼。
如圖所示神僵,數(shù)據(jù)綁定的語法有四種形式。每種形式都有一個(gè)方向 —— 綁定到 DOM 覆劈、綁定自 DOM 以及雙向綁定保礼。
HeroListComponent示例模板中有三種形式:
- {{hero.name}}[*插值表達(dá)式(https://www.angular.cn/docs/ts/latest/guide/displaying-data.html#interpolation)在<li>標(biāo)簽中顯示組件的hero.name屬性的值。
- [hero]屬性綁定把父組件HeroListComponent的selectedHero的值傳到子組件HeroDetailComponent的hero屬性中墩崩。
- (click) 事件綁定在用戶點(diǎn)擊英雄的名字時(shí)調(diào)用組件的selectHero
方法。
雙向數(shù)據(jù)綁定是重要的第四種綁定形式侯勉,它使用ngModel指令組合了屬性綁定和事件綁定的功能鹦筹。 下面是HeroDetailComponent模板的范例:
<input [(ngModel)]="hero.name">
在雙向綁定中,數(shù)據(jù)屬性值通過屬性綁定從組件流到輸入框址貌。用戶的修改通過事件綁定流回組件铐拐,把屬性值設(shè)置為最新的值徘键。
Angular 在每個(gè) JavaScript 事件循環(huán)中處理所有的數(shù)據(jù)綁定,它會從組件樹的根部開始遍蟋,遞歸處理全部子組件吹害。
數(shù)據(jù)綁定在模板與對應(yīng)組件的交互中扮演了重要的角色。
數(shù)據(jù)綁定在父組件與子組件的通訊中也同樣重要虚青。
5.指令 (directive)
Angular 模板是動(dòng)態(tài)的它呀。當(dāng) Angular 渲染它們時(shí),它會根據(jù)指令提供的操作對 DOM 進(jìn)行轉(zhuǎn)換棒厘。
組件是一個(gè)帶模板的指令纵穿;@Component裝飾器實(shí)際上就是一個(gè)@Directive裝飾器,只是擴(kuò)展了一些面向模板的特性奢人。
雖然嚴(yán)格來說組件就是一個(gè)指令谓媒,但是組件非常獨(dú)特,并在 Angular 中位于中心地位何乎,所以在架構(gòu)概覽中句惯,我們把組件從指令中獨(dú)立了出來。還有兩種其它類型的指令:結(jié)構(gòu)型指令和屬性 (attribute) 型指令支救。
它們往往像屬性 (attribute) 一樣出現(xiàn)在元素標(biāo)簽中抢野, 偶爾會以名字的形式出現(xiàn),但多數(shù)時(shí)候還是作為賦值目標(biāo)或綁定目標(biāo)出現(xiàn)搂妻。
結(jié)構(gòu)型指令通過在 DOM 中添加蒙保、移除和替換元素來修改布局。
下面的范例模板中用到了兩個(gè)內(nèi)置的結(jié)構(gòu)型指令:
[ngFor(https://www.angular.cn/docs/ts/latest/guide/displayingdata.html#ngFor)告訴 Angular 為heroes列表中的每個(gè)英雄生成一個(gè)li標(biāo)簽欲主。
[ngIf](https://www.angular.cn/docs/ts/latest/guide/displaying-data.html#ngIf)表示只有在選擇的英雄存在時(shí)邓厕,才會包含HeroDetail
組件。
屬性型 指令修改一個(gè)現(xiàn)有元素的外觀或行為扁瓢。 在模板中详恼,它們看起來就像是標(biāo)準(zhǔn)的 HTML 屬性,故名
ngModel指令就是屬性型指令的一個(gè)例子引几,它實(shí)現(xiàn)了雙向數(shù)據(jù)綁定昧互。 ngModel修改現(xiàn)有元素(一般是<input>)的行為:設(shè)置其顯示屬性值,并響應(yīng) change 事件伟桅。
<input [(ngModel)]="hero.name">
Angular 還有少量指令敞掘,它們或者修改結(jié)構(gòu)布局(例如 ngSwitch), 或者修改 DOM 元素和組件的各個(gè)方面(例如 ngStyle和 ngClass)楣铁。
當(dāng)然玖雁,我們也能編寫自己的指令。像HeroListComponent這樣的組件就是一種自定義指令盖腕。
6.服務(wù)
服務(wù)是一個(gè)廣義范疇赫冬,包括:值浓镜、函數(shù),或應(yīng)用所需的特性劲厌。
幾乎任何東西都可以是一個(gè)服務(wù)膛薛。 典型的服務(wù)是一個(gè)類,具有專注的补鼻、明確的用途哄啄。它應(yīng)該做一件特定的事情,并把它做好辽幌。
- 日志服務(wù)
- 數(shù)據(jù)服務(wù)
- 消息總線
- 稅款計(jì)算器
- 應(yīng)用程序配置
服務(wù)沒有什么特別屬于 Angular 的特性增淹。 Angular 對于服務(wù)也沒有什么定義。 它甚至都沒有定義服務(wù)的基類乌企,也沒有地方注冊一個(gè)服務(wù)虑润。
即便如此,服務(wù)仍然是任何 Angular 應(yīng)用的基礎(chǔ)加酵。組件就是最大的服務(wù)消費(fèi)者拳喻。
下面是一個(gè)服務(wù)類的范例,用于把日志記錄到瀏覽器的控制臺:
下面是HeroService類猪腕,用于獲取英雄數(shù)據(jù)冗澈,并通過一個(gè)已解析的承諾 (Promise) 返回它們。
HeroService還依賴于Logger服務(wù)和另一個(gè)用于處理服務(wù)器通訊BackendService服務(wù)陋葡。
組件類應(yīng)保持精簡亚亲。組件本身不從服務(wù)器獲得數(shù)據(jù)、不進(jìn)行驗(yàn)證輸入腐缤,也不直接往控制臺寫日志捌归。 它們把這些任務(wù)委托給服務(wù)。
組件的任務(wù)就是提供用戶體驗(yàn)岭粤,僅此而已惜索。它介于視圖(由模板渲染)和應(yīng)用邏輯(通常包括模型的某些概念)之間。 設(shè)計(jì)良好的組件為數(shù)據(jù)綁定提供屬性和方法剃浇,把其它瑣事都委托給服務(wù)巾兆。
Angular 不會強(qiáng)制要求我們遵循這些原則。 即使我們花 3000 行代碼寫了一個(gè)“廚房洗碗槽”組件虎囚,它也不會抱怨什么角塑。
Angular 幫助我們遵循這些原則 —— 它讓我們能輕易地把應(yīng)用邏輯拆分到服務(wù),并通過依賴注入來在組件中使用這些服務(wù)淘讥。
7.依賴注入
“依賴注入”是提供類的新實(shí)例的一種方式圃伶,還負(fù)責(zé)處理好類所需的全部依賴。大多數(shù)依賴都是服務(wù)适揉。 Angular 使用依賴注入來提供新組件以及組件所需的服務(wù)留攒。
Angular 通過查看構(gòu)造函數(shù)的參數(shù)類型得知組件需要哪些服務(wù)。 例如嫉嘀,HeroListComponent組件的構(gòu)造函數(shù)需要一個(gè)HeroService服務(wù):
constructor(private service: HeroService) { }
當(dāng) Angular 創(chuàng)建組件時(shí)炼邀,會首先為組件所需的服務(wù)請求一個(gè)注入器(injector)。
注入器維護(hù)了一個(gè)服務(wù)實(shí)例的容器剪侮,存放著以前創(chuàng)建的實(shí)例拭宁。 如果所請求的服務(wù)實(shí)例不在容器中,注入器就會創(chuàng)建一個(gè)服務(wù)實(shí)例瓣俯,并且添加到容器中杰标,然后把這個(gè)服務(wù)返回給 Angular。 當(dāng)所有請求的服務(wù)都被解析完并返回時(shí)彩匕,Angular 會以這些服務(wù)為參數(shù)去調(diào)用組件的構(gòu)造函數(shù)腔剂。 這就是依賴注入 。
HeroService注入的過程差不多是這樣的:
如果注入器還沒有HeroService驼仪,它怎么知道該如何創(chuàng)建一個(gè)呢掸犬?
簡單點(diǎn)說,我們必須先用注入器(injector)為HeroService
注冊一個(gè)提供商(provider)绪爸。 提供商用來創(chuàng)建或返回服務(wù)湾碎,通常就是這個(gè)服務(wù)類本身(相當(dāng)于new HeroService())。
我們可以在模塊中或組件中注冊提供商奠货。但通常會把提供商添加到根模塊上介褥,以便在任何地方都使用服務(wù)的同一個(gè)實(shí)例。
把它注冊在組件級表示該組件的每一個(gè)新實(shí)例都會有一個(gè)服務(wù)的新實(shí)例递惋。
需要記住的關(guān)于依賴注入的要點(diǎn)是:
依賴注入滲透在整個(gè) Angular 框架中柔滔,被到處使用。
- 注入器 (injector) 是本機(jī)制的核心丹墨。
廊遍。注入器負(fù)責(zé)維護(hù)一個(gè)容器,用于存放它創(chuàng)建過的服務(wù)實(shí)例贩挣。
喉前。注入器能使用提供商創(chuàng)建一個(gè)新的服務(wù)實(shí)例。 - 提供商是一個(gè)用于創(chuàng)建服務(wù)的配方王财。
- 把提供商注冊到注入器卵迂。
總結(jié)
我們學(xué)到的這些只是關(guān)于 Angular 應(yīng)用程序的八個(gè)主要構(gòu)造塊的基礎(chǔ)知識:
模塊
組件
模板
元數(shù)據(jù)
數(shù)據(jù)綁定
指令
服務(wù)
依賴注入
這是 Angular 應(yīng)用程序中所有其它東西的基礎(chǔ),要使用 Angular绒净,以這些作為開端就綽綽有余了见咒。 但它仍然沒有包含我們需要知道的全部。
這里是一個(gè)簡短的挂疆、按字母排序的列表改览,列出了其它重要的 Angular 特性和服務(wù)下翎。 它們大多數(shù)已經(jīng)(或即將)包括在這份開發(fā)文檔中:
動(dòng)畫:用 Angular 的動(dòng)畫庫讓組件動(dòng)起來,而不需要對動(dòng)畫技術(shù)或 CSS 有深入的了解宝当。
變更檢測:變更檢測文檔會告訴你 Angular 是如何決定組件的屬性值變化视事,什么時(shí)候該更新到屏幕, 以及它是如何利用區(qū)域 (zone) 來攔截異步活動(dòng)并執(zhí)行變更檢測策略庆揩。
事件:事件文檔會告訴你如何使用組件和服務(wù)觸發(fā)支持發(fā)布和訂閱的事件俐东。
表單:通過基于 HTML 的驗(yàn)證和臟檢查機(jī)制支持復(fù)雜的數(shù)據(jù)輸入場景。
HTTP:通過 HTTP 客戶端,可以與服務(wù)器通訊,以獲得數(shù)據(jù)褐筛、保存數(shù)據(jù)和觸發(fā)服務(wù)端動(dòng)作。
生命周期鉤子:通過實(shí)現(xiàn)生命周期鉤子接口砌庄,可以切入組件生命中的幾個(gè)關(guān)鍵點(diǎn):從創(chuàng)建到銷毀。
管道:在模板中使用管道轉(zhuǎn)換成用于顯示的值奕枢,以增強(qiáng)用戶體驗(yàn)鹤耍。例如,currency
管道表達(dá)式:
price | currency:'USD':true
它把價(jià)格“42.33”顯示為$42.33
路由器:在應(yīng)用程序客戶端的頁面間導(dǎo)航验辞,并且不離開瀏覽器稿黄。
測試:使用 Angular 測試平臺,在你的應(yīng)用部件與 Angular 框架交互時(shí)進(jìn)行單元測試跌造。