在用戶使用應用程序時,Angular
的路由器能讓用戶從一個視圖導航到另外一個視圖。html
Angular
的 Router
(即「路由器」)把瀏覽器中的 URL
看作一個操做指南, 據此導航到一個視圖,並能夠把參數傳給支撐視圖的相應組件,幫它決定具體該展示哪些內容。
路由器還在瀏覽器的歷史日誌中記錄下這些活動,這樣瀏覽器的前進和後退按鈕也能照常工做。數組
base href
元素,來告訴路由器該如何合成導航用的 URL
。 須要在index.html
的 <head>
標籤下先添加一個 <base>
元素。
src/index.html
瀏覽器
<base href="/">
複製代碼
Angular
的路由器是一個可選的服務,它用來呈現指定的 URL
所對應的視圖。 它並非 Angular
核心庫的一部分,而是在它本身的 @angular/router
包中。bash
src/app/app.module.ts
app
import { RouterModule, Routes } from '@angular/router';
複製代碼
路由器須要先配置纔會有路由信息。 下面的例子建立了五個路由定義,並用 RouterModule.forRoot
方法來配置路由器, 並把它的返回值添加到 AppModule
的 imports
數組中。this
src/app/app.module.ts
url
const appRoutes: Routes = [
{ path: 'crisis-center', component: CrisisListComponent },
{ path: 'hero/:id', component: HeroDetailComponent },
{
path: 'heroes',
component: HeroListComponent,
data: { title: 'Heroes List' }
},
{
path:'portal',
loadChildren: './settings/settings.module#SettingsModule'
}
{ path: '',
redirectTo: '/heroes',
pathMatch: 'full'
},
{ path: '**', component: PageNotFoundComponent }
];
@NgModule({
imports: [
RouterModule.forRoot(
appRoutes,
{ enableTracing: true } // <-- debugging purposes only
)
// other imports here
],
...
})
export class AppModule { }
複製代碼
這裏的路由數組 appRoutes
描述如何進行導航。 把它傳給 RouterModule.forRoot
方法並傳給本模塊的 imports
數組就能夠配置路由器。
每一個 Route
都會把一個 URL
的 path
映射到一個組件。
注意,path
不能以斜槓(/)
開頭,能夠以(../)
開頭。spa
第二個路由中的 :id
是一個路由參數的令牌(Token)
。好比 /hero/42
這個 URL
中,「42」
就是 id
參數的值。debug
第三個路由中的 data
屬性用來存放於每一個具體路由有關的任意信息。該數據能夠被任何一個激活路由訪問,並能用來保存諸如 頁標題、麪包屑以及其它靜態只讀數據。設計
第四個路由中咱們沒有將 ettingsModule
導入到咱們的 AppModule
中,而是經過 loadChildren
屬性來告訴 Angular
路由依據 loadChildren
屬性配置的路徑去加載 SettingsModule
模塊。這就是模塊懶加載功能的具體應用,當用戶訪問 /settings/**
路徑的時候,纔會加載對應的 SettingsModule
模塊,這減小了應用啓動時加載資源的大小。 另外咱們傳遞一個字符串做爲 loadChildren
的屬性值,該字符串由三部分組成:
(1)須要導入模塊的相對路徑
(2)#
分隔符
(3)導出模塊類的名稱
第五個路由中的空路徑('')
表示應用的默認路徑,當 URL
爲空時就會訪問那裏,所以它一般會做爲起點。 這個默認路由會重定向到 URL
/heroes
,並顯示 HeroesListComponent
。
最後一個路由中的 ** 路徑是一個通配符。當所請求的 URL
不匹配前面定義的路由表中的任何路徑時,路由器就會選擇此路由。 這個特性可用於顯示「404 - Not Found」
頁,或自動重定向到其它路由。
這些路由的定義順序是刻意如此設計的。路由器使用先匹配者優先的策略來匹配路由,因此,具體路由應該放在通用路由的前面。在上面的配置中,帶靜態路徑的路由被放在了前面,後面是空路徑路由,所以它會做爲默認路由。而通配符路由被放在最後面,這是由於它能匹配上每個 URL
,所以應該只有在前面找不到其它能匹配的路由時才匹配它。
若是你想要看到在導航的生命週期中發生過哪些事件,可使用路由器默認配置中的 enableTracing
選項。它會把每一個導航生命週期中的事件輸出到瀏覽器的控制檯。 這應該只用於調試。你只須要把 enableTracing: true
選項做爲第二個參數傳給 RouterModule.forRoot()
方法就能夠了。
Routes
是路由配置數組。每一個都有如下屬性:
path
是路由匹配的路徑。pathMatch
是指定匹配策略的字符串。pathMatch:'full'
表示徹底匹配matcher
定義了路徑匹配並取代自定義策略path
和pathMatch
。component
是組件類型。redirectTo
是將替換當前匹配段的url
片斷。outlet
是組件應放入的插座的名稱。canActivate
控制是否容許進入路由。。canActivateChild
等同 canActivate
,只不過針對是全部子路由。。canDeactivate
控制是否容許離開路由。canLoad
控制是否容許延遲加載整個模塊。data
是提供給組件的附加數據,被激活路由訪問。resolve
是用於查找數據解析器的DI
令牌的映射。children
是子路由定義的數組。loadChildren
是對延遲加載子路由的引用。注意:路由守衛對於權限控制很是便利,固然其粒度固然只能在頁面層級。假若須要對按鈕粒度也只能利用指令的方式,而兩者的結合能夠極大的改善權限控制埋點的代碼量。
RouterModule.forChild()
與 Router.forRoot()
方法相似,但它只能應用在特性模塊中。
這個功能很是強大,由於咱們沒必要在一個地方(咱們的主模塊)定義全部路由信息。反之,咱們能夠在特性模塊中定義模塊特有的路由信息,並在必要的時候將它們導入咱們主模塊。RouterModule.forChild()
的使用方法以下:
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Routes, RouterModule } from '@angular/router';
export const ROUTES: Routes = [
{
path: 'settings',
component: SettingsComponent,
///settings 設置頁面下有 /settings/profile 和 /settings/password 兩個頁面
children: [
{ path: 'profile', component: ProfileSettingsComponent },
{ path: 'password', component: PasswordSettingsComponent }
]
}
];
@NgModule({
imports: [
CommonModule,
RouterModule.forChild(ROUTES)
],
// ...
})
export class ChildModule {}
複製代碼
經過以上示例,咱們知道在主模塊和特性模塊中,路由配置對象的類型是同樣的,區別只是主模塊和特性模塊中需調用不一樣的方法,來配置模塊路由。
RouterOutlet
是一個來自路由模塊中的指令,它的用法相似於組件。 它扮演一個佔位符的角色,用於在模板中標出一個位置,路由器將會把要顯示在這個出口處的組件顯示在這裏。
<router-outlet></router-outlet>
<!-- Routed components go here -->
複製代碼
有了這份配置,當本應用在瀏覽器中的 URL
變爲 /heroes
時,路由器就會匹配到 path
爲 heroes
的 Route
,並在宿主視圖中的RouterOutlet
以後顯示 HeroListComponent
組件。
1.路由配置
const routes: Routes = [
{ path: 'news',
component: NewsComponent,
outlet:'let1'
}
{ path: 'news',
component: News2Cmponent,
outlet:'let2'
}]
2.html點擊連接
<a routerLink = "[{ outlets: { let1: ['news'] } }]"></a>
<a routerLink = "[{ outlets: { let2: ['news'] } }]"></a
3.html路由出口
<router-outlet name="let1"></router-outlet>
<router-outlet name="let2"></router-outlet>
複製代碼
即訪問 /news/
時同時加載 NewsComponent
和 News2Cmponent
兩個組件
如今,你已經有了配置好的一些路由,還找到了渲染它們的地方,但又該如何導航到它呢?當然,從瀏覽器的地址欄直接輸入 URL
也能作到,可是大多數狀況下,導航是某些用戶操做的結果,好比點擊一個 A
標籤。
考慮下列模板:
src/app/app.component.html
<h1>Angular Router</h1>
<nav>
<a routerLink="/crisis-center" routerLinkActive="active">Crisis Center</a>
<a routerLink="/heroes" routerLinkActive="active">Heroes</a>
</nav>
<router-outlet></router-outlet>
複製代碼
a
標籤上的 RouterLink
指令讓路由器得以控制這個 a
元素。 這裏的導航路徑是固定的,所以能夠把一個字符串賦給 routerLink
(「一次性」綁定)。 routerLink
第一個路徑片斷能夠以 /
,./
或 ../
開頭:
若是以 /
開頭,路由將從根路由開始查找
若是以 ./
開頭或沒有使用 /
,則路由將從當前激活路由的子路由開始查找
若是以 ../
開頭,路由往上一級查找
若是須要更加動態的導航路徑,那就把它綁定到一個返回連接參數數組的模板表達式。 路由器會把這個數組解析成完整的 URL
。
例如使用 ['/team', teamId, 'user', userName, {details: true}]
數組,意味着咱們想要生成一個連接到 /team/11/user/bob;details=true
。
import { Router } from '@angular/router';
// ...
constructor(private router: Router) {}
// ...
this.router.navigate(['/detail', this.news.id])
this.router.navigate([{ outlets: { let2: null }}]);
複製代碼
navigateByUrl
方法指向完整的絕對路徑
<a routerLink="/user/bob" routerLinkActive="active">Bob</a>
複製代碼
RouterLinkActive
指令:當 URL
地址是 /user
或 /user/bob
時,當前的 RouterState
爲活動狀態,active
類將會被添加到 <a>
標籤上。若是 URL
發生變化,則 active
類將自動從 <a>
標籤上移除。
路由連接的激活狀態會向下級聯到路由樹中的每一個層級,因此,父子路由連接可能會同時激活。
只有當 URL
與當前 URL
精確匹配時纔會激活,能夠把 [routerLinkActiveOptions]
綁定爲 { exact: true }
表達式。
路由器的當前狀態(RouterState
):在導航時的每一個生命週期成功完成時,路由器會構建出一個 ActivatedRoute
組成的樹。
你能夠在應用中的任何地方用 Router
服務及其 routerState
屬性來訪問當前的 RouterState
值。
RouterState
中的每一個 ActivatedRoute
都提供了從任意激活路由開始向上或向下遍歷路由樹的一種方式,以得到關於父、子、兄弟路由的信息。
class MyComponent {
constructor(router: Router) {
const state: RouterState = router.routerState;
const snapshot: RouterStateSnapshot = state.snapshot;
const root: ActivatedRouteSnapshot = snapshot.root;
const child = root.firstChild;
const id: Observable<string> = child.params.map(p => p.id);
//...
}
}
複製代碼
該路由的路徑和參數能夠經過注入進來的一個名叫ActivatedRoute
的路由服務來獲取。 它有一大堆有用的信息,包括:
屬性 | 說明 |
---|---|
url |
路由路徑的 Observable 對象,是一個由路由路徑中的各個部分組成的字符串數組。 |
data |
一個 Observable ,其中包含提供給路由的 data 對象。也包含由解析守衛(resolve guard )解析而來的值。 |
paramMap |
一個 Observable ,其中包含一個由當前路由的必要參數和可選參數組成的map 對象。用這個 map 能夠獲取來自同名參數的單一值或多重值。 |
queryParamMap |
一個 Observable ,其中包含一個對全部路由都有效的查詢參數組成的map 對象。 用這個 map 能夠獲取來自查詢參數的單一值或多重值。 |
fragment |
一個適用於全部路由的 URL 的 fragment (片斷)的 Observable 。 |
outlet |
要把該路由渲染到的 RouterOutlet 的名字。對於無名路由,它的路由名是 primary ,而不是空串。 |
routeConfig |
用於該路由的路由配置信息,其中包含原始路徑。 |
parent |
當該路由是一個子路由時,表示該路由的父級 ActivatedRoute 。 |
firstChild |
包含該路由的子路由列表中的第一個 ActivatedRoute 。 |
children |
包含當前路由下全部已激活的子路由。 |
//獲取路由參數
private route: ActivatedRoute,
this.username = this.route
.queryParamMap
.pipe(map(params => this.username = params.username));
複製代碼
在每次導航中,Router
都會經過 Router.events
屬性發布一些導航事件。這些事件的範圍涵蓋了從開始導航到結束導航之間的不少時間點。下表中列出了所有導航事件:
路由器事件 | 說明 |
---|---|
NavigationStart |
本事件會在導航開始時觸發。 |
RouteConfigLoadStart |
本事件會在 Router 惰性加載 某個路由配置以前觸發。 |
RouteConfigLoadEnd |
本事件會在惰性加載了某個路由後觸發。 |
RoutesRecognized |
本事件會在路由器解析完 URL ,並識別出了相應的路由時觸發 |
GuardsCheckStart| 本事件會在路由器開始 Guard 階段以前觸發。 |
|
ChildActivationStart |
本事件會在路由器開始激活路由的子路由時觸發。 |
ActivationStart |
本事件會在路由器開始激活某個路由時觸發。 |
GuardsCheckEnd |
本事件會在路由器成功完成了 Guard 階段時觸發。 |
ResolveStart |
本事件會在 Router 開始解析(Resolve )階段時觸發。 |
ResolveEnd |
本事件會在路由器成功完成了路由的解析(Resolve )階段時觸發。 |
ChildActivationEnd |
本事件會在路由器激活了路由的子路由時觸發。 |
ActivationEnd |
本事件會在路由器激活了某個路由時觸發。 |
NavigationEnd |
本事件會在導航成功結束以後觸發。 |
NavigationCancel |
本事件會在導航被取消以後觸發。 這多是由於在導航期間某個路由守衛返回了 false 。 |
NavigationError |
這個事件會在導航因爲意料以外的錯誤而失敗時觸發。 |
Scroll |
本事件表明一個滾動事件。 |
當啓用了 enableTracing
選項時,這些事件也同時會記錄到控制檯中。要想查看對路由導航事件進行過濾的例子,請訪問 Angular
中的可觀察對象一章的路由器部分
適用於後臺管理等須要登陸才能使用的模塊
// app/auth.service.ts
import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
@Injectable()
export class AuthService implements CanActivate {
canActivate() {
// 這裏判斷登陸狀態, 返回 true 或 false
return true;
}
}
複製代碼
// app/app.router.ts
// 增長 CanActivate
import { CanActivate ... } from '@angular/router';
// 配置中增長 canActivate 如:
{ path: 'admin', canActivate:[AuthService] ... }
複製代碼
該應用有一個配置過的路由器。 外殼組件中有一個 RouterOutlet
,它能顯示路由器所生成的視圖。 它還有一些 RouterLink
,用戶能夠點擊它們,來經過路由器進行導航。
下面是一些路由器中的關鍵詞彙及其含義:
路由器部件 | 含義 |
---|---|
Router (路由器) |
爲激活的 URL 顯示應用組件。管理從一個組件到另外一個組件的導航。ts->this.router.navigateByUrl("/protel") |
RouterModule |
一個獨立的 Angular 模塊,用於提供所需的服務提供商,以及用來在應用視圖之間進行導航的指令。ts->RouterModule.forRoot(Routers數組,ExtraOptions對象) |
Routes (路由數組) |
定義了一個路由數組,每個都會把一個 URL 路徑映射到一個組件。ts->[(path:'',componet: ***)] |
Route (路由) |
定義路由器該如何根據 URL 模式(pattern )來導航到組件。大多數路由都由路徑和組件類構成。 |
RouterOutlet (路由出口) |
該指令(<router-outlet> )用來標記出路由器該在哪裏顯示視圖。 |
RouterLink (路由連接) |
這個指令把可點擊的 HTML 元素綁定到某個路由。點擊帶有 routerLink 指令(綁定到字符串或連接參數數組)的元素時就會觸發一次導航。html-><a [routerLink]="[./order]"></a> |
RouterLinkActive (活動路由連接) |
當 HTML 元素上或元素內的routerLink 變爲激活或非激活狀態時,該指令爲這個 HTML 元素添加或移除 CSS 類。html中 |
ActivatedRoute (激活的路由) |
爲每一個路由組件提供的一個服務,它包含特定於路由的信息,好比路由參數、靜態數據、解析數據、全局查詢參數和全局碎片(fragment )。ts中 |
RouterState (路由器狀態) |
路由器的當前狀態包含了一棵由程序中激活的路由構成的樹。它包含一些用於遍歷路由樹的快捷方法。 |
連接參數數組 | 這個數組會被路由器解釋成一個路由操做指南。你能夠把一個RouterLink 綁定到該數組,或者把它做爲參數傳給Router.navigate 方法。 |
路由組件 | 一個帶有RouterOutlet 的 Angular 組件,它根據路由器的導航來顯示相應的視圖。 |