app/index.html
添加路由說明。
由于當(dāng)前項目的根目錄是app,所以添加如下代碼:
<base href="/">
路由模塊已經(jīng)從Angular中分離出來,所以我們在使用時要導(dǎo)入:
import { RouterModule, Routes } from '@angular/router';
現(xiàn)在可以來寫一個簡單的路由配置,我們將路由放置到一個模塊中:
// app/modules/app-routing.module.ts
import { NgModule } from '@angular/core';
import {Routes, RouterModule} from '@angular/router';
import {DemoComponentComponent} from '../demo/demo-component/demo-component.component';
const routes: Routes = [
{ path: 'demoComponent', component: DemoComponentComponent},
...
{ path: '**', component: DemoComponentComponent }
];
@NgModule({
imports: [
RouterModule.forRoot(routes)
],
exports: [RouterModule]
})
export class AppRoutingModule { }
在上面的代碼中,我們定義了一個路由數(shù)組,每一個都會把一個URL路徑(path
)映射到一個組件。
最后的**
是路由通配符,當(dāng)所有其上面的路由路徑都不符合(包括無效路徑)時,就會采取通配符路由。
注意:
RouterModule.forChild()
path
不能以斜杠(/
)開頭// app.module.ts
...
import { AppComponent } from './app.component';
import {AppRoutingModule} from './modules/app-routing.module';
@NgModule({
...
imports: [
...
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
有了路由導(dǎo)航,我們還需要一個容器來顯示對應(yīng)的組件內(nèi)容:
<router-outlet></router-outlet>
添加如上代碼后,當(dāng)路由切換(路由模塊中存在的路由)時,對應(yīng)的組件會顯示在其之后。
注:可以參考app/app.component.html
。
注(來源官網(wǎng)):路由器使用先匹配者優(yōu)先的策略來匹配路由,所以,具體路由應(yīng)該放在通用路由的前面。在上面的配置中,帶靜態(tài)路徑的路由被放在了前面,后面是空路徑路由,因此它會作為默認路由。而通配符路由被放在最后面,這是因為它能匹配上每一個URL,因此應(yīng)該只有在前面找不到其它能匹配的路由時才匹配它。
既然是路由導(dǎo)航,除了可以直接在瀏覽器的地址欄輸入地址跳轉(zhuǎn)外,我們更多時候需要一系列可以點擊的鏈接元素(比如a,button):
<a routerLink="/demoComponent">創(chuàng)建組件</a>
由于導(dǎo)航路徑是固定的,所以我們將一個字符串賦給routerLink
。
注:a標簽上的RouterLink
指令讓路由器得以控制這個a元素。
當(dāng)然,如果我們需要更復(fù)雜的路由路徑,我們可以使用鏈接參數(shù)數(shù)組:
[routerLink] = ['/demoComponent', 'id']
[routerLink] = ['/demoComponent', { name: 'route', id: 123}]
一般情況下,我們會為當(dāng)前激活的路徑鏈接添加一些高亮效果,這時我們可以利用routerLinkActive
屬性:
<a routerLink="/demoComponent" routerLinkActive="active">創(chuàng)建組件</a>
它的值是一個以空格分割的CSS樣式類列表。
還可以是一個CSS類數(shù)組:
[routerLinkActive]="['...']"
注(來源官網(wǎng)):RouterLinkActive
指令會基于當(dāng)前的RouterState
對象來為激活的RouterLink
切換CSS類。 這會一直沿著路由樹往下進行級聯(lián)處理,所以父路由鏈接和子路由鏈接可能會同時激活。 要改變這種行為,可以把[routerLinkActiveOptions]綁定到{exact: true}
表達式。 如果使用了{ exact: true }
,那么只有在其URL與當(dāng)前URL精確匹配時才會激活指定的RouterLink。
重定向
在路由配置中,我們還可以添加重定向參數(shù):
{ path: '', redirectTo: '/demoComponent', pathMatch: 'full' }
注:重定向路由需要一個pathMatch
屬性,來告訴路由器如何用URL去匹配路由的路徑,否則路由器就會報錯。
路由參數(shù)
在配置路由時,我們還可以定義路由參數(shù):
// app/modules/app-routing.module.ts
{ path: 'demoRouter/:id', component: DemoRouterComponent}
比如輸入http://localhost:4200/demoRouter/123,然后我們需要通過ActivatedRoute
服務(wù)來獲取這些路由參數(shù):
// demo-router.component.ts
import { Component, OnInit } from '@angular/core';
import {ActivatedRoute} from '@angular/router';
...
export class DemoRouterComponent implements OnInit {
id: any;
constructor(private route: ActivatedRoute) {
this.route.params.subscribe(param => {
this.id = param['id'];
})
}
...
}
在上面的代碼中,我們注入ActivatedRoute
服務(wù)并定義了一個私有屬性route
,然后通過route.params
屬性來獲取路由參數(shù),ActivatedRoute.params
是一個路由參數(shù)的可觀察對象,所以我們要通過subscribe()
方法來訪問。
注:所有的路由參數(shù)或查詢參數(shù)都是字符串。
子路由
子路由也是我們常用的,定義也很簡單:
// app/modules/app-routing.module.ts
import {DemoChildRouterComponent} from '../demo/demo-child-router/demo-child-router.component';
const routes: Routes = [
...
{
path: 'demoRouter2', component: DemoRouter2Component,
children: [{
path: 'child',
component: DemoChildRouterComponent
}]
}
];
子路由組件:
// app/demo/demo-child-router.component.html
<div class="box">
我是子路由
</div>
前面說過我們要給路由添加視圖容器,子路由也是一樣,不過子路由的視圖容器要放在另一個組件中:
// app/demo/demo-router2.component.html
<div class="box">
<a routerLink="/demoRouter2/child">訪問子路由</a>
</div>
<router-outlet></router-outlet>
當(dāng)我們點擊上面的鏈接時,你會看到瀏覽器地址欄變?yōu)椋?b>http://localhost:4200/demoRouter2/child,組件DemoChildRouterComponent
中的模板就會顯示出來。
路由動畫
對于路由,我們還可以添加動畫,但使用動畫之前,我們要安裝動畫模塊(Angular4后動畫模塊分離出來了):
npm install @angular/animations --save
然后在主模塊app.module.ts
中注冊:
...
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
@NgModule({
declarations: [... ],
imports: [
...
BrowserAnimationsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
我們添加一個具有動畫的子路由:
// app/modules/app-routing.module.ts
import {DemoChildRouter2Component} from '../demo/demo-child-router/demo-child-router2.component';
const routes: Routes = [
...
{
path: 'demoRouter2', component: DemoRouter2Component,
children: [
...
{
path: 'child2',
component: DemoChildRouter2Component
}]
}
];
對于DemoChildRouter2Component
組件,我們修改如下:
// demo/demo-child-router2.component.html
import {Component, HostBinding, OnInit} from '@angular/core';
import {animate, state, style, trigger, transition} from '@angular/animations';
@Component({
selector: 'app-demo-child-router2',
templateUrl: './demo-child-router2.component.html',
styleUrls: ['./demo-child-router2.component.scss'],
animations: [
trigger('fadeInUpState', [
state('in', style({opacity: 1, transform: 'translate3d(0, 0, 0)'})),
transition('void => *', [
style({
opacity: 0,
transform: 'translate3d(0, 100%, 0)'
}), animate('.4s cubic-bezier(.25,.8,.25,1)')
])
])
]
})
export class DemoChildRouter2Component implements OnInit {
@HostBinding('@fadeInUpState') fadeInUpState;
@HostBinding('style.display') display = 'block';
constructor() { }
}
對于@HostBinding()
是屬性裝飾器,用來給宿主設(shè)置屬性。在這里我們將動畫@fadeInUpState
添加到宿主上,同時還將宿主的display
的值設(shè)置為block
。
注意:給宿主添加動畫,一定要設(shè)置`display`的值,因為默認自定義元素的display
是空字符串,CSS動畫是不起作用的。
關(guān)于動畫的更多細節(jié),可以看《動畫(Animation)》一章。
異步路由
隨著項目越來越大,我們一般不會將所有組件都添加到主模塊中,這時我們可以根據(jù)不同路由的;奧惰性加載不同的模塊:
const routes: Routes = [
...
{
path: 'demoRouter2',
component: DemoRouter2Component,
children: [
...
{
path: 'loadModule',
loadChildren: 'app/demo/demo-router-load.module#RouterLoadModule',
}]
}
];
當(dāng)路由器導(dǎo)航到這個路由時,它會用loadChildren
字符串來動態(tài)加載RouterLoadModule
,然后把RouterLoadModule
添加到當(dāng)前的路由配置中, 最后,它把所請求的路由加載到目標DemoRouterLoadComponent
組件中。
RouterLoadModule
代碼如下:
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {DemoRouterLoadComponent} from './demo-router-load.component';
import {DemoRouterLoadRougingModule} from './demo-router-load-routing.module';
@NgModule({
imports: [CommonModule, DemoRouterLoadRougingModule],
declarations: [DemoRouterLoadComponent]
})
export class RouterLoadModule {}
仔細看的話,你會發(fā)現(xiàn)一個新的子路由模塊DemoRouterLoadRougingModule
,它是用來加載異步路由配置的:
// demo-router-load-routing.module.ts
import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {DemoRouterLoadComponent} from './demo-router-load.component';
const routes: Routes = [
{
path: '',
component: DemoRouterLoadComponent
}
]
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class DemoRouterLoadRougingModule {}
使用:
// demo-router2.component.html
<a routerLink="/demoRouter2/loadModule">訪問異步路由</a>
當(dāng)你點擊上面的鏈接時,你可以打開控制臺看看Network看看會多了一個加載文件:
更多建議: