? ? ? ?這里給大家簡單的總結(jié)下Angular2路由器相關(guān)的一些信息孤紧。但是我一向認為最好的文檔還是官方文檔启泣,還是推薦大家參考官方文檔 https://www.angular.cn/guide/router#displaying-multiple-routes-in-named-outlets幔虏。
? ? ? ?路由器簡單來說就是讓用戶從一個視圖導航到另一個視圖达址。
一、路由器相關(guān)對象介紹
? ? ? ?如果在我們的Angular應用里面想使用路由衡未,首先我們需要做兩件事情。
- 在index.html的 <head> 標簽下添加一個 <base> 元素,來告訴路由器該如何合成導航用的URL扯夭。通常在index.html的head部分添加如下代碼。
<base href="/">
- 在AppModule里面的imports里面導入RouterModule鞍匾。
1.1交洗、路由器-Router
? ? ? ?每個帶路由的Angular應用都有一個Router(路由器)服務(wù)的單例對象。當瀏覽器的URL變化時橡淑,路由器會查找對應的Route(路由)藕筋,并據(jù)此決定該顯示哪個組件。路由器需要先配置路由才會有路由信息梳码。
路由器-Router就是為激活的URL顯示相應的組件隐圾。管理從一個組件到另一個組件的導航。
? ? ? ?路由器必須需要先配置路由信息掰茶。并用 RouterModule.forRoot方法來配置路由器暇藏,并把它的返回值添加到AppModule的imports數(shù)組中。
1.2濒蒋、路由數(shù)組-Routes
? ? ? ?路由配置的時候需要先定義一個路由數(shù)組盐碱。路由數(shù)組描述如何進行導航。每個Route都會把一個URL的path 映射到一個組件沪伙。 注意瓮顽,path 不能以斜杠(/)開頭。 路由器會為解析和構(gòu)建最終的 URL围橡,這樣當你在應用的多個視圖之間導航時暖混,可以任意使用相對路徑和絕對路徑。
定義路由數(shù)組之后需要調(diào)用RouterModule.forRoot()方法把路由數(shù)組配置進入路由器里面去翁授。
? ? ? ?比如如下的代碼Heroes模塊對應的路由模塊里面heroesRoutes就一個路由數(shù)組拣播,然后我們調(diào)用RouterModule.forChild(heroesRoutes)把他配置到路由里面去來晾咪。
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {RouterModule, Routes} from '@angular/router';
import {HeroListComponent} from './hero-list.component';
import {HeroDetailComponent} from './hero-detail.component';
const heroesRoutes: Routes = [
{path: 'heroes', component: HeroListComponent},
{path: 'hero/:id', component: HeroDetailComponent}
];
@NgModule({
imports: [
CommonModule,
RouterModule.forChild(heroesRoutes)
],
declarations: [],
exports: [
RouterModule
]
})
export class HeroesRoutingModule {
}
關(guān)于路由Route對象屬性說明,下面還會有更加詳細的介紹
屬性 | 類型 | 說明 |
---|---|---|
path | string | 路由地址(不能以'/'開頭) |
pathMatch | string | 指定路由匹配策略的字符串(pathMatch有兩個值:full贮配、prefix) |
matcher | UrlMatcher | 自定義路徑匹配谍倦,取代自定義策略path和pathMatch |
component | Type<any> | 路由映射的組件 |
redirectTo | string | 路由重定向地址 |
outlet | string | 路由出口名稱<router-outlet>標簽里面name字段名稱 |
canActivate | any[] | 路由守衛(wèi)接口,控制是否允許進入路由 |
canActivateChild | any[] | 路由守衛(wèi)接口泪勒,控制是否允許進入子路由 |
canDeactivate | any[] | 路由守衛(wèi)接口昼蛀,控制是否允許離開路由 |
canLoad | any[] | 路由守衛(wèi)接口,控制是否允許延遲加載整個模塊 |
data | Data | 用來存放于路由有關(guān)的任意信息(組件需要的附加數(shù)據(jù)) |
resolve | ResolveData | 用于在路由激活之前獲取路由數(shù)據(jù) |
children | Routes | 子路由數(shù)組 |
loadChildren | LoadChildren | 是對延遲加載子路由的引用 |
runGuardsAndResolvers | RunGuardsAndResolvers |
1.3圆存、路由出口 - RouterOutlet
? ? ? ?有路由了曹洽,也把路由數(shù)組配置到路由里面去了。但是我們的路由對應的組件在哪里展示呢辽剧。這個時候就需要路由出口了送淆。路由出口對應模板里面的<router-outlet> 標簽。路由出口是路由器渲染的地方怕轿,用來標記路由器該在哪里顯示對應的視圖偷崩。
1.4、路由器鏈接-Router links
? ? ? ?路由器鏈接把可點擊的HTML元素綁定到某個路由撞羽。點擊帶有 routerLink指令(綁定到字符串或鏈接參數(shù)數(shù)組)的元素時就會觸發(fā)一次導航阐斜。比如下面的代碼,我們就定義了兩個路由鏈接crisis-center诀紊、heroes谒出。
template: `
<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>
`
? ? ? ?還是上述代碼中,RouterLinkActive指令會基于當前的RouterState對象來為激活的 RouterLink 切換CSS類邻奠。 他會一直沿著路由樹往下進行級聯(lián)處理笤喳,所以父路由鏈接和子路由鏈接可能會同時激活。 要改變這種行為碌宴,可以把 [routerLinkActiveOptions] 綁定到 {exact: true} 表達式杀狡。 如果使用了 { exact: true },那么只有在其URL與當前URL精確匹配時才會激活指定的RouterLink贰镣。
<a routerLink="/crisis-center" routerLinkActive="active"
[routerLinkActiveOptions]="{exact: true}">Bob</a>
1.5呜象、路由器狀態(tài) - Router state
? ? ? ?在導航時的每個生命周期成功完成時,路由器會構(gòu)建出一個ActivatedRoute 組成的樹碑隆,它表示路由器的當前狀態(tài)恭陡。 你可以在應用中的任何地方用Router 服務(wù)及其routerState屬性來訪問當前的RouterState值。
1.6上煤、激活的路由 - ActivatedRoute
? ? ? ?ActivatedRoute是為每個路由組件提供提供的一個服務(wù)休玩,它包含特定于路由的信息,比如路由參數(shù)、靜態(tài)數(shù)據(jù)哥捕、解析數(shù)據(jù)、全局查詢參數(shù)和全局碎片(fragment)嘉熊。它有一大堆有用的信息遥赚,包括:
屬性 | 說明 |
---|---|
url | 路由路徑的 Observable 對象,是一個由路由路徑中的各個部分組成的字符串數(shù)組 |
data | 一個 Observable阐肤,其中包含提供給路由的 data 對象凫佛。也包含由解析守衛(wèi)(resolve guard)解析而來的值 |
paramMap | 一個 Observable,其中包含一個由當前路由的必要參數(shù)和可選參數(shù)組成的map對象孕惜。用這個 map 可以獲取來自同名參數(shù)的單一值或多重值 |
queryParamMap | 一個 Observable愧薛,其中包含一個對所有路由都有效的查詢參數(shù)組成的map對象。 用這個 map 可以獲取來自查詢參數(shù)的單一值或多重值 |
fragment | 一個適用于所有路由的 URL 的 fragment(片段)的 Observable |
outlet | 要把該路由渲染到的 RouterOutlet 的名字衫画。對于無名路由毫炉,它的路由名是 primary,而不是空串 |
routeConfig | 用于該路由的路由配置信息削罩,其中包含原始路徑 |
parent | 當該路由是一個子路由時瞄勾,表示該路由的父級 ActivatedRoute |
firstChild | 包含該路由的子路由列表中的第一個 ActivatedRoute |
children | 包含當前路由下所有已激活的子路由 |
? ? ? ?比如如下的代碼,當路由導航到HeroDetailComponent組件的時候弥激,我們通過ActivatedRoute從路由里面獲取id进陡。
? ? ? ?
import {Component, HostBinding, OnInit} from '@angular/core';
import {slideInDownAnimation} from '../animations';
import {Observable} from 'rxjs';
import {Hero, HeroService} from './hero.service';
import {ActivatedRoute, Router} from '@angular/router';
@Component({
selector: 'app-hero-detail',
templateUrl: './hero-detail.component.html',
styleUrls: ['./hero-detail.component.css'],
animations: [slideInDownAnimation]
})
export class HeroDetailComponent implements OnInit {
@HostBinding('@routeAnimation') routeAnimation = true;
@HostBinding('style.display') display = 'block';
@HostBinding('style.position') position = 'absolute';
hero$: Observable<Hero>;
constructor(
private route: ActivatedRoute,
private router: Router,
private service: HeroService
) {
}
ngOnInit() {
// 一進來界面就先獲取id對應的Hero 有兩種方式
// 第一種(最保險的方式)
// this.hero$ = this.route.paramMap.pipe(
// switchMap((params: ParamMap) =>
// this.service.getHero(params.get('id')))
// );
// 第二種方式,快照的方式
const id = this.route.snapshot.paramMap.get('id');
this.hero$ = this.service.getHero(id);
}
gotoHeroes(hero: Hero) {
const heroId = hero ? hero.id : null;
// id 和 foo 不會影響到/heroes的路由
this.router.navigate(['/heroes', {id: heroId, foo: 'foo'}]);
}
}
1.7微服、路由事件
? ? ? ?在每次導航中趾疚,Router都會通過Router.events 屬性發(fā)布一些導航事件。這些事件的范圍涵蓋了從開始導航到結(jié)束導航之間的很多時間點以蕴。下表中列出了全部導航事件:
Router.events是一個Observable對象
路由器事件 | 說明 |
---|---|
NavigationStart | 事件會在導航開始時觸發(fā) |
RoutesRecognized | 事件會在路由器解析完 URL糙麦,并識別出了相應的路由時觸發(fā) |
RouteConfigLoadStart |
事件會在 Router 對一個路由配置進行惰性加載之前觸發(fā)
RouteConfigLoadEnd | 事件會在路由被惰性加載之后觸發(fā)
NavigationEnd | 事件會在導航成功結(jié)束之后觸發(fā)
NavigationCancel | 事件會在導航被取消之后觸發(fā)。 這可能是因為在導航期間某個路由守衛(wèi)返回了 false
NavigationError | 事件會在導航由于意料之外的錯誤而失敗時觸發(fā)
? ? ? ?比如如下的代碼丛肮,教我們怎么來獲取路由事件
import {Component, HostBinding} from '@angular/core';
import {slideInDownAnimation} from '../animations';
import {NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router, RoutesRecognized} from '@angular/router';
import {filter} from 'rxjs/operators';
@Component({
selector: 'app-crisis-detail',
templateUrl: './crisis-detail.component.html',
styleUrls: ['./crisis-detail.component.css'],
animations: [slideInDownAnimation]
})
export class CrisisDetailComponent {
@HostBinding('@routeAnimation') routeAnimation = true;
@HostBinding('style.display') display = 'block';
@HostBinding('style.position') position = 'absolute';
constructor(
private router: Router
) {
// 監(jiān)聽路由變化
router.events.subscribe(event => {
if (event instanceof NavigationStart) {
console.log('NavigationStart');
} else if (event instanceof NavigationEnd) {
console.log('NavigationEnd');
} else if (event instanceof NavigationCancel) {
console.log('NavigationCancel');
} else if (event instanceof NavigationError) {
console.log('NavigationError');
} else if (event instanceof RoutesRecognized) {
console.log('NavigationError');
}
});
this.router.events.pipe(
filter((event: Event) => event instanceof NavigationEnd)
).subscribe(x => console.log(x));
}
}
1.8喳资、路由動畫
? ? ? ?路由動畫用于在路由進入和退出的時候天劍轉(zhuǎn)場動畫。使用路由動畫需要先導入BrowserAnimationsModule模塊腾供。每個動畫對應一個動畫文件(.ts文件)仆邓。關(guān)于路由動畫的部分我們后面有機會在仔細的研究研究。實例里面可以參考animations.ts問下的寫法和使用伴鳖。
二节值、路由守衛(wèi)
? ? ? ?路由守衛(wèi)簡單來說就是通過機制來控制那些路由可以被那些用戶訪問。說白了就會特定的路由需要有特定的權(quán)限才能訪問榜聂。路由的守衛(wèi)可以返回一個 Observable<boolean> 或 Promise<boolean>搞疗,并且路由器會等待這個可觀察對象被解析為 true 或 false。true表明有權(quán)限訪問须肆,false表示無權(quán)限訪問匿乃。
? ? ? ?路由守衛(wèi)提供的守衛(wèi)接口有:
守衛(wèi)接口 | 解釋 |
---|---|
CanActivate | 控制是否允許進入路由 |
CanActivateChild | 控制是否允許進入子路由 |
CanDeactivate | 控制是否允許離開路由 |
Resolve | 處理再在路由激活之前獲取路由數(shù)據(jù)的情況 |
CanLoad | 控制是否允許延遲加載整個模塊 |
? ? ? ?在分層路由的每個級別上桩皿,可以設(shè)置多個守衛(wèi)。 路由器會先按照從最深的子路由由下往上檢查的順序來檢查 CanDeactivate()和 CanActivateChild()守衛(wèi)幢炸。 然后它會按照從上到下的順序檢查CanActivate()守衛(wèi)泄隔。 如果特性模塊是異步加載的,在加載它之前還會檢查CanLoad()守衛(wèi)宛徊。 如果任何一個守衛(wèi)返回false佛嬉,其它尚未完成的守衛(wèi)會被取消,這樣整個導航就被取消了闸天。
? ? ? ?路由守衛(wèi)一般在路由配置里面配置暖呕,可以參考實例里面admin-routing.module.ts文件的路由配置。關(guān)于路由守衛(wèi)所有的例子可以參考文章末尾DEMO里面的admin模塊里面的內(nèi)容苞氮。
2.1湾揽、CanActivate
? ? ? ?CanActivate用來處理進入當前路由的情況,返回true允許進入笼吟,返回false則不允許進入钝腺。對應路由配置里面的canActivate字段,他的配置可以是一個數(shù)組一旦某個返回false就認為認證失敗赞厕,則不允許進入當前路由艳狐。
2.1、CanActivateChild
? ? ? ?CanActivateChild用來處理進入子路由的情況皿桑,會在任何子路由被激活之前運行毫目。和CanActivate的用法一樣,一個控制當前路由诲侮,一個控制子路由镀虐。
2.1、CanDeactivate
? ? ? ?CanDeactivate用來處理從當前路由離開的情況沟绪。比如我們可以控制是允許離開當前路由刮便,或者在離開之前給出提示啥的。
2.1绽慈、Resolve
? ? ? ?你想想當路由切換的時候恨旱,被路由的頁面中的元素(標簽)就會立馬顯示出來,同時坝疼,數(shù)據(jù)會被準備好并呈現(xiàn)出來搜贤。但是注意,數(shù)據(jù)和元素并不是同步的钝凶,在沒有任何設(shè)置的情況下仪芒,AngularJS默認先呈現(xiàn)出元素,而后再呈現(xiàn)出數(shù)據(jù)。這樣就會導致頁面會被渲染兩遍掂名,導致“頁面UI抖動”的問題据沈,對用戶不太友好。resolve就是來解決了這個問題的饺蔑。Resolve守衛(wèi)主要是在路由激活之前獲取路由數(shù)據(jù)锌介,預先加載數(shù)據(jù)。
? ? ? ?具體可以參考文章末尾DEMO里面crisis-detail.component.ts文件CrisisDetailComponent組件的使用膀钠,注意crisis-center-routing.module.ts里面路由配置掏湾。
2.1裹虫、CanLoad
? ? ? ?CanLoad控制是否允許延遲加載整個模塊肿嘲。說白了就是只有通過了我的判斷你才能娶加載整個模塊。具體可以參見文章末尾DEMO里面app-routing.module.ts里面路由數(shù)組里面admin路徑的配置筑公。
? ? ? ?最后也給出根據(jù)官方文檔敲出來的例子的下載地址DEMO下載地址雳窟。關(guān)于路由咱們就先說這么多,其實路由里面的東西咱們要學的還是很多的匣屡,咱也是個初學者封救。就當做個筆記了。還是強烈推薦大家去看官方文檔 https://www.angular.cn/guide/router#milestone-5-route-guards