Angular2路由器(路由+導航)

? ? ? ?這里給大家簡單的總結(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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末捣作,一起剝皮案震驚了整個濱河市誉结,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌券躁,老刑警劉巖惩坑,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異也拜,居然都是意外死亡以舒,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門慢哈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蔓钟,“玉大人,你說我怎么就攤上這事卵贱±哪” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵键俱,是天一觀的道長佣谐。 經(jīng)常有香客問我,道長方妖,這世上最難降的妖魔是什么狭魂? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上雌澄,老公的妹妹穿的比我還像新娘斋泄。我一直安慰自己,他們只是感情好镐牺,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布炫掐。 她就那樣靜靜地躺著,像睡著了一般睬涧。 火紅的嫁衣襯著肌膚如雪募胃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天畦浓,我揣著相機與錄音痹束,去河邊找鬼。 笑死讶请,一個胖子當著我的面吹牛祷嘶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播夺溢,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼论巍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了风响?” 一聲冷哼從身側(cè)響起嘉汰,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎状勤,沒想到半個月后鞋怀,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡荧降,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年接箫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片朵诫。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡辛友,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出剪返,到底是詐尸還是另有隱情废累,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布脱盲,位于F島的核電站邑滨,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏钱反。R本人自食惡果不足惜掖看,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一匣距、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧哎壳,春花似錦毅待、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至刹泄,卻和暖如春外里,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背特石。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工盅蝗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人县匠。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓风科,卻偏偏與公主長得像撒轮,于是被迫代替她去往敵國和親乞旦。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容