Angular-路由

路由與導航

在用戶使用應用程序時,Angular 的路由器能讓用戶從一個視圖導航到另外一個視圖html

概覽

AngularRouter(即「路由器」)把瀏覽器中的 URL 看作一個操做指南, 據此導航到一個視圖,並能夠把參數傳給支撐視圖的相應組件,幫它決定具體該展示哪些內容。
路由器還在瀏覽器的歷史日誌中記錄下這些活動,這樣瀏覽器的前進和後退按鈕也能照常工做。數組

基礎知識

base href元素,來告訴路由器該如何合成導航用的 URL。 須要在index.html<head> 標籤下先添加一個 <base> 元素。
src/index.html瀏覽器

<base href="/">
複製代碼

從路由庫中導入

Angular 的路由器是一個可選的服務,它用來呈現指定的 URL 所對應的視圖。 它並非 Angular 核心庫的一部分,而是在它本身的 @angular/router 包中。bash

src/app/app.module.tsapp

import { RouterModule, Routes } from '@angular/router';
複製代碼

配置

路由器須要先配置纔會有路由信息。 下面的例子建立了五個路由定義,並用 RouterModule.forRoot 方法來配置路由器, 並把它的返回值添加到 AppModuleimports 數組中。this

src/app/app.module.tsurl

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 都會把一個 URLpath 映射到一個組件
注意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定義了路徑匹配並取代自定義策略pathpathMatch
  • component 是組件類型。
  • redirectTo 是將替換當前匹配段的url片斷。
  • outlet 是組件應放入的插座的名稱。
  • canActivate控制是否容許進入路由。。
  • canActivateChild等同 canActivate,只不過針對是全部子路由。。
  • canDeactivate控制是否容許離開路由。
  • canLoad控制是否容許延遲加載整個模塊。
  • data是提供給組件的附加數據,被激活路由訪問。
  • resolve是用於查找數據解析器的DI令牌的映射。
  • children 是子路由定義的數組。
  • loadChildren是對延遲加載子路由的引用。

注意:路由守衛對於權限控制很是便利,固然其粒度固然只能在頁面層級。假若須要對按鈕粒度也只能利用指令的方式,而兩者的結合能夠極大的改善權限控制埋點的代碼量。

RouterModule.forChild()

RouterModule.forChild()Router.forRoot() 方法相似,但它只能應用在特性模塊中。

  • 友情提示:根模塊中使用 forRoot(),子模塊中使用 forChild()

這個功能很是強大,由於咱們沒必要在一個地方(咱們的主模塊)定義全部路由信息。反之,咱們能夠在特性模塊中定義模塊特有的路由信息,並在必要的時候將它們導入咱們主模塊。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 時,路由器就會匹配到 pathheroesRoute,並在宿主視圖中的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/ 時同時加載 NewsComponentNews2Cmponent 兩個組件

路由器連接

如今,你已經有了配置好的一些路由,還找到了渲染它們的地方,但又該如何導航到它呢?當然,從瀏覽器的地址欄直接輸入 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

  • ts中跳轉寫法
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 一個適用於全部路由的 URLfragment(片斷)的 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方法。
路由組件 一個帶有RouterOutletAngular 組件,它根據路由器的導航來顯示相應的視圖。
相關文章
相關標籤/搜索