版本:4.0.0+2
此時(shí)AppComponent
做了所有的事情慨蓝。起初,它顯示一個(gè)單一英雄的詳情竹伸。然后泥栖,它成了有一列英雄和英雄詳情的主從結(jié)構(gòu)。很快會(huì)有新的需求和功能勋篓。你不能把所有功能堆積在一個(gè)組件中吧享;那樣不利于維護(hù)。
你需要把它拆分到子組件生巡,每個(gè)組件專注于特定的任何或工作流程耙蔑。最終,AppComponent
會(huì)成為一個(gè)簡(jiǎn)單的包含這些子組件的殼孤荣。
在本章,你將通過提取英雄詳情到一個(gè)獨(dú)立的须揣、可復(fù)用的組件朝那方向邁出第一步盐股。當(dāng)你做完這一切,應(yīng)用看起來應(yīng)該這樣——在線示例 (查看源碼)耻卡。
我們離開的地方
在開始本章之前疯汁,先檢查一下,是否已經(jīng)有了如下目錄結(jié)構(gòu)卵酪。如果沒有幌蚊,回到上一章谤碳。
如果應(yīng)用不運(yùn)行了,啟動(dòng)應(yīng)用溢豆。當(dāng)你做出修改時(shí)蜒简,通過刷新瀏覽器保持繼續(xù)運(yùn)行。
制作英雄詳情組件
創(chuàng)建一個(gè)名為hero_detail_component.dart
的文件漩仙。這個(gè)文件有一個(gè)新的 HeroDetailComponent
搓茬。
Angular 慣例
如下所示垢啼,開始編寫HeroDetailComponent
:
// lib/src/hero_detail_component.dart (initial version)
import 'package:angular/angular.dart';
import 'package:angular_forms/angular_forms.dart';
@Component(
selector: 'hero-detail',
directives: const [CORE_DIRECTIVES, formDirectives],
)
class HeroDetailComponent {
}
要定義組件私爷,總是要導(dǎo)入主要的 Angular 庫(kù)。
@Component
注解為組件提供了 Angular 元數(shù)據(jù)膊夹。CSS 選擇器名hero-detail
將會(huì)匹配元素標(biāo)簽衬浑,以識(shí)別在父組件模板內(nèi)的本組件。在本教程快結(jié)束的部分放刨,你將添加一個(gè)<hero-detail>
元素到AppComponent
模板工秩。
英雄詳情模板
要移動(dòng)英雄詳情視圖到HeroDetailComponent
,從AppComponent
模板的底部剪切英雄詳情內(nèi)容进统,并把它粘貼到新的@Component
注解的template
參數(shù)中助币。
HeroDetailComponent
有一個(gè) hero,而不是 selectedHero螟碎。使用 ”hero“ 替換模板中的每一處 ”selectedHero“眉菱。當(dāng)你昨晚這一切,新的模板看起來這樣:
// lib/src/hero_detail_component.dart (template)
template: '''
<div *ngIf="hero != null">
<h2>{{hero.name}} details!</h2>
<div><label>id: </label>{{hero.id}}</div>
<div>
<label>name: </label>
<input [(ngModel)]="hero.name" placeholder="name">
</div>
</div>''',
添加 hero 屬性
HeroDetailComponent
模板綁定到組件的hero
屬性掉分。把這個(gè)屬性及其必備的導(dǎo)入一塊添加到HeroDetailComponent
類俭缓。
// lib/src/hero_detail_component.dart (hero)
import 'hero.dart';
class HeroDetailComponent {
Hero hero;
}
hero 屬性是一個(gè)輸入屬性
在本章稍后的部分,父組件AppComponent
通過綁定它的selectedHero
屬性到HeroDetailComponent
的hero
屬性來會(huì)告訴子組件HeroDetailComponent
顯示哪個(gè)英雄酥郭。綁定看起來是這樣的:
<hero-detail [hero]="selectedHero"></hero-detail>
放在等號(hào) (=
) 左邊方括號(hào)中的hero
屬性华坦,使其成為了屬性綁定表達(dá)式的目標(biāo)。你必須聲明一個(gè)目標(biāo)綁定屬性為一個(gè)輸入屬性不从。否則惜姐,Angular 拒絕綁定,并拋出一個(gè)錯(cuò)誤椿息。
通過使用@Input
注解歹袁,聲明hero
是一個(gè)輸入屬性:
// lib/src/hero_detail_component.dart (Input annotation)
@Input()
Hero hero;
更多關(guān)于輸入屬性的內(nèi)容坷衍,請(qǐng)看屬性指令。
沒錯(cuò)条舔。hero
屬性是HeroDetailComponent
類中唯一的東西枫耳。它做的事情就是通過它的hero
輸入屬性接收一個(gè)英雄對(duì)象,然后使用它的模板綁定到該屬性逞刷。下面是完成后的HeroDetailComponent
嘉涌。
// lib/src/hero_detail_component.dart
import 'package:angular/angular.dart';
import 'package:angular_forms/angular_forms.dart';
import 'hero.dart';
@Component(
selector: 'hero-detail',
template: '''
<div *ngIf="hero != null">
<h2>{{hero.name}} details!</h2>
<div><label>id: </label>{{hero.id}}</div>
<div>
<label>name: </label>
<input [(ngModel)]="hero.name" placeholder="name">
</div>
</div>''',
directives: const [CORE_DIRECTIVES, formDirectives],
)
class HeroDetailComponent {
@Input()
Hero hero;
}
添加 HeroDetailComponent 到 AppComponent
AppComponent
仍然是主從結(jié)構(gòu)的視圖。在你從模板中剪切出那一部分之前夸浅,它被用來在它自身上顯示英雄詳情÷刈睿現(xiàn)在,它將委托給HeroDetailComponent
帆喇。
首先導(dǎo)入HeroDetailComponent
以使AppComponent
可以引用它警医。
import 'src/hero_detail_component.dart';
想想那個(gè)在HeroDetailComponent
元數(shù)據(jù)中的 CSS 選擇器hero-detail
。那就是表示HeroDetailComponent
元素的標(biāo)簽名坯钦。
在靠近AppComponent
模板的底部添加<hero-detail>
元素预皇,那里是之前英雄詳情待的地方。
通過綁定AppComponent
的selectedHero
屬性到HeroDetailComponent
的hero
屬性婉刀,協(xié)調(diào)主組件AppComponent
和HeroDetailComponent
吟温。
<hero-detail [hero]="selectedHero"></hero-detail>
現(xiàn)在每次selectedHero
發(fā)生變化,HeroDetailComponent
就獲取一個(gè)新的英雄來顯示突颊。
修改后的AppComponent
模板看起來是這樣:
// lib/app_component.html
<h1>{{title}}</h1>
<h2>My Heroes</h2>
<ul class="heroes">
<li *ngFor="let hero of heroes"
[class.selected]="hero === selectedHero"
(click)="onSelect(hero)">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
</ul>
<hero-detail [hero]="selectedHero"></hero-detail>
每次用戶選擇一個(gè)新英雄詳情信息應(yīng)該會(huì)更新鲁豪。然而現(xiàn)在什么事都沒發(fā)生!點(diǎn)擊一個(gè)英雄律秃。沒有詳情信息爬橡。如果你在瀏覽器開發(fā)工具的控制臺(tái)尋找錯(cuò)誤。沒有錯(cuò)誤棒动。
這好像是 Angular 忽略了新標(biāo)簽糙申。原因就是它忽略了新的標(biāo)簽。
指令列表
瀏覽器會(huì)忽視它無法識(shí)別的 HTML 標(biāo)簽和屬性(attribute)船惨,Angular同樣如此柜裸。
你已經(jīng)導(dǎo)入HeroDetailComponent
,并在模板中使用了<hero-detail>
掷漱,但是你并沒有告訴Angular粘室。
正如你之前為內(nèi)置 Angular 指令所做的,通過在元數(shù)據(jù)directives
列表中列出英雄詳情組件來告訴 Angular卜范。你再也不需要formDirectives
了,所以刪除它以及在文件頂部的angular_forms
導(dǎo)入:
// lib/app_component.dart (directives)
directives: const [CORE_DIRECTIVES, HeroDetailComponent],
刷新瀏覽器鹿榜。應(yīng)用正常工作了海雪。
應(yīng)用設(shè)計(jì)變化
像之前一樣锦爵,每當(dāng)用戶點(diǎn)擊了一個(gè)英雄的名字,該英雄的詳情就顯示在了英雄列表的下方奥裸。但現(xiàn)在险掀,HeroDetailComponent
用來顯示那些詳情。
把原來的AppComponent
重構(gòu)成兩個(gè)組件帶來如下收益湾宙,無論是現(xiàn)在還是將來:
- 你通過減少
AppComponent
的職責(zé)簡(jiǎn)化了該組件樟氢。 - 你可以把
HeroDetailComponent
改進(jìn)成一個(gè)功能豐富的英雄編輯器,而不用改動(dòng)父組件AppComponent
侠鳄。 - 你可以改進(jìn)
AppComponent
埠啃,而不用改動(dòng)英雄詳情視圖。 - 將來你可以在其它組件的模板中重復(fù)使用
HeroDetailComponent
伟恶。
回顧應(yīng)用結(jié)構(gòu)
驗(yàn)證你是否有如下結(jié)構(gòu):
你已經(jīng)走過的路
在本章中你完成的內(nèi)容如下:
- 創(chuàng)建了一個(gè)可復(fù)用的組件碴开。
- 學(xué)會(huì)了如何讓一個(gè)組件接收輸入。
- 學(xué)會(huì)了在
directives
列表中聲明應(yīng)用指令博秫。 - 學(xué)會(huì)了把父組件綁定到子組件潦牛。
應(yīng)用看起來應(yīng)該這樣——在線示例 (查看源碼)。
下一步