路由是導(dǎo)航的另一個(gè)名字腾节。路由器就是從一個(gè)視圖導(dǎo)航到另一個(gè)視圖的機(jī)制。
1.導(dǎo)航媚朦,那么我們專門做一個(gè)導(dǎo)航組件。這個(gè)組件只是導(dǎo)航使用日戈。一般導(dǎo)航的都是第一個(gè)頁面询张,而我們現(xiàn)在啟動的就是app.component.ts。
但是此頁面目前顯示的是列表涎拉,我們需要修改下瑞侮,修改成從主頁導(dǎo)航到列表頁。
那么我們?nèi)绱俗觯?br>
(1)把a(bǔ)pp.component.ts文件改名為heroes.component.ts鼓拧。
(2)把AppComponent類改名為HeroesComponent(注意半火,只在這一個(gè)文件中改名)。
(3)把a(bǔ)pp-test選擇器改名為'app-my-heroes'季俩。
2.創(chuàng)建導(dǎo)航頁面钮糖,即新的app.component.ts。
新的AppComponent將成為應(yīng)用的“殼”酌住。 它將在頂部放一些導(dǎo)航鏈接店归,并且把我們要導(dǎo)航到的頁面放在下面的顯示區(qū)中。
執(zhí)行下列步驟(請嚴(yán)格按照此步驟做酪我,不能跳):
(1)創(chuàng)建一個(gè)名叫src/app/app.component.ts的新文件消痛。
(2)添加支持性的import語句。
(3)定義一個(gè)導(dǎo)出的 AppComponent類都哭。
(4)在類的上方添加@Component元數(shù)據(jù)裝飾器秩伞,裝飾器帶有app-test選擇器。
(5)將下面的項(xiàng)目從HeroesComponent移到AppComponent:
(5.1)title類屬性
(5.2)@Component模板中的<h1>標(biāo)簽欺矫,它包含了對title屬性的綁定纱新。
(5.3)在模板的標(biāo)題下面添加<app-my-heroes>標(biāo)簽,以便我們?nèi)阅芸吹接⑿哿斜怼?br>
(6)添加HeroesComponent組件到根模塊的declarations數(shù)組中穆趴,以便 Angular 能認(rèn)識<app-my-heroes>標(biāo)簽脸爱。組件都需要添加到此處。
(7)添加HeroService到AppModule的providers數(shù)組中未妹,因?yàn)槲覀兊拿恳粋€(gè)視圖都需要它簿废。
(8)從HerosComponent的providers數(shù)組中移除HeroService,因?yàn)樗惶岬侥K了络它。
(9)為AppComponent添加一些import語句捏鱼。
實(shí)際文件:app.component.ts文件
import { Component } from '@angular/core';
@Component({
selector: 'app-test',
template: `
<h1>{{title}}</h1>
<my-heroes></my-heroes>//這個(gè)就是列表頁面
`
})
export class AppComponent {
title = 'Tour of Heroes';
}
app.module.ts文件:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { HeroDetailComponent } from './hero-detail.component';
import { HeroesComponent } from './heroes.component';//包含
import { HeroService } from './hero.service';//包含
@NgModule({
imports: [
BrowserModule,
FormsModule
],
declarations: [
AppComponent,
HeroDetailComponent,
HeroesComponent//添加這個(gè)
],
providers: [//移到此
HeroService
],
bootstrap: [ AppComponent ]
})
export class AppModule {
}
上面2步其實(shí)沒有做實(shí)際的東西,就是拆成2個(gè)組件而已酪耕,沒有做實(shí)際意義的路由的處理导梆。
3.現(xiàn)在開始處理路由:
(1)打開index.html,確保它的<head>區(qū)頂部有一個(gè)<base href="/">元素
(2)配置路由迂烁。app.module.ts中
(2.1)import { RouterModule } from '@angular/router';
(2.2)
imports: [
BrowserModule,
FormsModule, // <-- import the FormsModule before binding with [(ngModel)]
RouterModule.forRoot([//放到這里
{
path: 'heroes',
component: HeroesComponent
}
])
],
(3)修改app.component.ts的模板:
template: <h1>{{title}}</h1> <a routerLink="/heroes">Heroes</a> <router-outlet></router-outlet>//顯示路由到的組件的內(nèi)容
這樣就可以實(shí)現(xiàn)路由了看尼。
注意:這個(gè)時(shí)候模板中的routerLink的屬性值和app.module.ts中的path的關(guān)系可以看明白了。這就是路由切換了盟步,比較簡單的藏斩。
路由定義包括以下部分:
(1)Path: 路由器會用它來匹配瀏覽器地址欄中的地址,如heroes却盘。
(2)Component: 導(dǎo)航到此路由時(shí)狰域,路由器需要創(chuàng)建的組件(HeroesComponent)媳拴。
那個(gè)forroot是什么意思?下回分解兆览。
4.添加路由屈溉,其實(shí)很簡單,不信抬探,再添加一個(gè)試試子巾。
(1)添加一個(gè)新文件dashboard.component.ts然后內(nèi)容寫上:
import { Component } from '@angular/core';
@Component({
selector: 'app-my-dashboard',
template: '<h3>My Dashboard</h3>'
})
export class DashboardComponent { }
(2)配置新的路由:
RouterModule.forRoot([
{
path: 'heroes',
component: HeroesComponent
},
{
path: 'dashboard',//添加一個(gè)這個(gè)而已
component: DashboardComponent
}
])
(3)將新的組件添加到module,這個(gè)很簡單小压,大家都應(yīng)該知道如何添加了线梗。先import { HeroesComponent } from './heroes.component';包含它,然后
declarations: [
HeroDetailComponent,
HeroesComponent,
AppComponent,
DashboardComponent//放到這里
],
這樣就包含了怠益。
(4)這樣就算是準(zhǔn)備好了仪搔。再來,這個(gè)是使用:
改變app.component.ts的模板:
template: `
<h1>{{title}}</h1>
<a routerLink="/heroes">Heroes</a>
<router-outlet></router-outlet>
<a routerLink="/dashboard">Dashboard</a>
<router-outlet></router-outlet>
`
這樣就是兩個(gè)頁面切換了蜻牢,很簡單吧僻造。
注:上面的寫法有點(diǎn)啰嗦,可以如此寫:
template: `
<h1>{{title}}</h1>
<a routerLink="/heroes">Heroes</a>
<a routerLink="/dashboard">Dashboard</a>
<router-outlet></router-outlet>
`
5.添加重定向孩饼,讓啟動就顯示一個(gè)組件:
RouterModule.forRoot([
{
path: 'heroes',
component: HeroesComponent
},
{
path: 'dashboard',
component: DashboardComponent
},
{
path: '',//路徑是根
redirectTo: '/dashboard',//重定向了
pathMatch: 'full'
}
])
也是很簡單的髓削。
6.美化下dashboard.component這個(gè)組件:
(1)dashboard.component.ts文件修改為:
import { Component, OnInit } from '@angular/core';
import { Hero } from './hero';
import { HeroService } from './hero.service';//包含service
@Component({
selector: 'app-my-dashboard',
templateUrl: './dashboard.component.html',//使用文件顯示
})
export class DashboardComponent implements OnInit {
heroes: Hero[] = [];
constructor(private heroService: HeroService) { }//構(gòu)造方法申明私有變量
ngOnInit(): void {//初始化,使用承諾接口
this.heroService.getHeroes()
.then(heroes => this.heroes = heroes.slice(1, 5));
}
}
(2)添加dashboard.component.html文件镀娶,內(nèi)容如下:
<h3>Top Heroes</h3>
<div class="grid grid-pad">
<div *ngFor="let hero of heroes" class="col-1-4">
<div class="module hero">
<h4>{{hero.name}}</h4>
</div>
</div>
</div>
美化完成了立膛。數(shù)據(jù)使用的服務(wù)的數(shù)據(jù)。
7.路由到詳情梯码,并傳遞數(shù)據(jù)宝泵。前面到詳情頁面,是使用的<app-hero-detail [hero]="selectedHero"></app-hero-detail>這種方式來傳遞對象的⌒ⅲ現(xiàn)在儿奶,我們使用路由的方式導(dǎo)航到詳情頁面,現(xiàn)在開始改造:
(1)在app.module.ts中做一個(gè)參數(shù)化的路由:
{
path: 'detail/:id',//路徑中的冒號 (:) 表示:id是一個(gè)占位符鳄抒,當(dāng)導(dǎo)航到這個(gè)HeroDetailComponent組件時(shí)闯捎,它將被填入一個(gè)特定英雄的id。
component: HeroDetailComponent
}
(2)改造hero-detail.component.ts為:
// Keep the Input import for now, you'll remove it later:
import { Component, Input, OnInit } from '@angular/core';
import { ActivatedRoute, ParamMap } from '@angular/router';
import { Location } from '@angular/common';
import { HeroService } from './hero.service';
import 'rxjs/add/operator/switchMap';
import { Hero } from './hero';
@Component({
selector: 'app-hero-detail',
templateUrl: './hero-detail.component.html',//模板變化
})
export class HeroDetailComponent implements OnInit {
constructor(
private heroService: HeroService,
private route: ActivatedRoute,
private location: Location
) {}
@Input() hero: Hero;
ngOnInit(): void {
this.route.paramMap
.switchMap((params: ParamMap) => this.heroService.getHero(+params.get('id')))
.subscribe(hero => this.hero = hero);
}
goBack(): void {
this.location.back();//利用瀏覽器的歷史堆棧许溅,導(dǎo)航到上一步
}
}
switchMap運(yùn)算符如何將可觀察的路由參數(shù)中的 id 映射到一個(gè)新的Observable瓤鼻, 即HeroService.getHero()方法的結(jié)果。
如果用戶在 getHero 請求執(zhí)行的過程中再次導(dǎo)航這個(gè)組件贤重,switchMap 再次調(diào)用HeroService.getHero()之前茬祷, 會取消之前的請求。
英雄的id是數(shù)字并蝗,而路由參數(shù)的值總是字符串祭犯。 所以我們需要通過 JavaScript 的 (+) 操作符把路由參數(shù)的值轉(zhuǎn)成數(shù)字秸妥。
(3)在hero.service.ts中添加:
···
getHero(id: number): Promise<Hero> {
return this.getHeroes()
.then(heroes => heroes.find(hero => hero.id === id));
}//根據(jù)ID獲取到信息
···
(4)添加hero-detail.component.html文件:
···
<div *ngIf="hero">
<h2>{{hero.name}} details!</h2>
<div>
<label>id: </label>{{hero.id}}</div>
<div>
<label>name: </label>
<input [(ngModel)]="hero.name" placeholder="name" />
</div>
<button (click)="goBack()">Back</button>
</div>
···
(5)點(diǎn)擊時(shí),需要切到detail頁面沃粗,需要改造dashboard.component.html粥惧,能夠點(diǎn)擊和傳遞參數(shù):
<h3>Top Heroes</h3>
<div class="grid grid-pad">
<a *ngFor="let hero of heroes" [routerLink]="['/detail', hero.id]" class="col-1-4">//這里就是能夠點(diǎn)擊,并且傳遞了參數(shù)
<div class="module hero">
<h4>{{hero.name}}</h4>
</div>
</a>
</div>
現(xiàn)在就可以用路由的方式導(dǎo)航到detail頁面了陪每。還能傳遞參數(shù)呢影晓。
8.上面雖然可以使用了镰吵,但是路由的代碼太多檩禾,讓app.module.ts會越變越大,因此疤祭,需要將路由提取到一個(gè)單獨(dú)的文件盼产。
(1)做一個(gè)單獨(dú)的文件:app-routing.module.ts并寫代碼為:
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DashboardComponent } from './dashboard.component';
import { HeroesComponent } from './heroes.component';
import { HeroDetailComponent } from './hero-detail.component';
const routes: Routes = [
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
{ path: 'dashboard', component: DashboardComponent },
{ path: 'detail/:id', component: HeroDetailComponent },
{ path: 'heroes', component: HeroesComponent }
];//以后添加路由添加到此即可。
@NgModule({
imports: [ RouterModule.forRoot(routes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule {}
(2)修改app.module.ts勺馆,以便包含這個(gè)路由:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms'; // <-- NgModel lives here
import { AppComponent } from './app.component';
import { HeroDetailComponent } from './hero-detail.component';
import { HeroesComponent } from './heroes.component';
import { DashboardComponent } from './dashboard.component';
import { HeroService } from './hero.service';
import { AppRoutingModule } from './app-routing.module';//1戏售、包含它
@NgModule({
imports: [
BrowserModule,
FormsModule, // <-- import the FormsModule before binding with [(ngModel)]
AppRoutingModule//2.放到此,添加模塊
],
declarations: [
HeroDetailComponent,
HeroesComponent,
AppComponent,
DashboardComponent,
],
bootstrap: [ AppComponent ],
providers: [HeroService]
})
export class AppModule { }
通過上面2步草穆,就將路由單獨(dú)列出了灌灾。
9.也可以通過代碼跳轉(zhuǎn)到詳細(xì)頁面,當(dāng)然也是路由的方式悲柱。
(1).將heroes.component.ts中模板中的:
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
替換成一個(gè)按鈕:
<div *ngIf="selectedHero">
<h2>
{{selectedHero.name | uppercase}} is my hero
</h2>
<button (click)="gotoDetail()">View Details</button>//這個(gè)按鈕
</div>
(2)在類中:
import { Router } from '@angular/router';//1.包含
constructor(
private router: Router,
private heroService: HeroService) { }//2.構(gòu)造函數(shù)中申明
gotoDetail(): void {
this.router.navigate(['/detail', this.selectedHero.id]);//3.使用代碼跳轉(zhuǎn)
}