Angular2 之 路由與導(dǎo)航詳細介紹
導(dǎo)航是很簡單的,只是不同頁面之間的切換,路由是實現(xiàn)導(dǎo)航的一種。
一個url對應(yīng)的一個頁面,在angular2中是一個組件。定義一個規(guī)則。
基礎(chǔ)知識
大多數(shù)帶路由的應(yīng)用都要在index.html的標簽下先添加一個元素,來告訴路由器該如何合成導(dǎo)航用的URL。
路由是從@angular/router包中引入的。
路由都是需要進行配置的。而這個配置需要的也就是RouterModule模塊。
一個路由配置
path中不能用斜線/開頭。
這些路由的定義順序是故意如此設(shè)計的。 路由器使用先匹配者優(yōu)先的策略來匹配路由,所以,具體路由應(yīng)該放在通用路由的前面。在上面的配置中,帶靜態(tài)路徑的路由被放在了前面,后面是空路徑路由,因此它會作為默認路由。而通配符路由被放在最后面,這是因為它是最通用的路由,應(yīng)該只在前面找不到其它能匹配的路由時才匹配它。
const appRoutes: Routes = [ { path:'',// empty path匹配各級路由的默認路徑。 它還支持在不擴展URL路徑的前提下添加路由。 component: DashboardComponent },{ path: 'dashboard', component: DashboardComponent }, { path: 'loopback', component: LoopbackComponent }, { path: 'heroparent', component: HeroParentComponent }, { path:'version', component: VersionParentComponent }, { path: '**',// **代表該路由是一個通配符路徑。如果當前URL無法匹配上我們配置過的任何一個路由中的路徑,路由器就會匹配上這一個。當需要顯示404頁面或者重定向到其它路由時,該特性非常有用。 component: DashboardComponent, } ]; export const appRoutingModule: ModuleWithProviders = RouterModule.forRoot(appRoutes);
RouterOutlet - 路由插座
顯示路由器生成的視圖。在展示父路由的位置中的某個地方展示子路由對應(yīng)的地方。
路由模塊
最開始的路由,我們是直接寫在app.module.ts文件中的,像這樣,我們可以實現(xiàn)簡單的導(dǎo)航。
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { RouterModule, Routes } from '@angular/router'; import { AppComponent } from './app.component'; import { CrisisListComponent } from './crisis-list.component'; import { HeroListComponent } from './hero-list.component'; const appRoutes: Routes = [ { path: 'crisis-center', component: CrisisListComponent }, { path: 'heroes', component: HeroListComponent } ]; @NgModule({ imports: [ BrowserModule, FormsModule, RouterModule.forRoot(appRoutes) ], declarations: [ AppComponent, HeroListComponent, CrisisListComponent ], bootstrap: [ AppComponent ] }) export class AppModule { }
但是這樣不方便,所以我們要進行路由的分離,重構(gòu)成我們自己的路由模塊。like this:
const appRoutes: Routes = [ { path:'', component: DashboardComponent },{ path: 'dashboard', component: DashboardComponent }, { path: 'loopback', component: LoopbackComponent }, { path: 'heroparent', component: HeroParentComponent }, { path:'version', component: VersionParentComponent }, { path: '**', component: DashboardComponent, } ]; export const appRoutingModule: ModuleWithProviders = RouterModule.forRoot(appRoutes);
同樣我們還可以寫多個路由模塊。但是我們必須在app.module.ts中進行imports:[appRoutingModule]。
組件路由
我們需要將一些特征區(qū)域分割開來,做成自己單獨的模塊。必如hero模塊。在這里,我們需要hero單獨的導(dǎo)航,這也就是組件路由。
平級的路由
@NgModule({ imports: [ RouterModule.forChild([ { path: 'heroes', component: HeroListComponent }, { path: 'hero/:id', component: HeroDetailComponent }, { path:'heroform', component: HeroFormComponent }, ]) ], exports: [ RouterModule ] }) export class HeroRoutingModule { }
我們還有另外一中類型的路由組織方式,路由樹的形式。
const crisisCenterRoutes: Routes = [ { path: '', redirectTo: '/crisis-center', pathMatch: 'full' }, { path: 'crisis-center', component: CrisisCenterComponent, children: [ { path: '', component: CrisisListComponent, children: [ { path: ':id', component: CrisisDetailComponent, }, { path: '', component: CrisisCenterHomeComponent } ] } ] } ]; @NgModule({ imports: [ RouterModule.forChild(crisisCenterRoutes) ], exports: [ RouterModule ] }) export class CrisisCenterRoutingModule { }
重定向路由
添加一個redirect路由,它會把初始的相對URL(”)悄悄翻譯成默認路徑(/crisis-center)。
{ path: '', redirectTo: '/crisis-center', pathMatch: 'full' },
路由守衛(wèi)
簡介
路由守衛(wèi),應(yīng)用在這個路由不是對所有導(dǎo)航都有效的,是有一些前置條件的,只有當這些前置條件滿足的時候,才能被導(dǎo)航到該頁面。
可以在路由配置中添加守衛(wèi)來進行處理。守衛(wèi)可以返回一個boolean值,為true時,導(dǎo)航過程繼續(xù),為false時,導(dǎo)航被取消,當然這時候也可以被導(dǎo)航到其他頁面。也可以返回返回一個Observable<boolean>或Promise<boolean>,并且路由器會等待這個可觀察對象被解析為true或false。
路由器支持多種守衛(wèi)
用CanActivate來處理導(dǎo)航到某路由的情況。
用CanActivateChild處理導(dǎo)航到子路由的情況。
用CanDeactivate來處理從當前路由離開的情況。
用Resolve在路由激活之前獲取路由數(shù)據(jù)。
用CanLoad來處理異步導(dǎo)航到某特性模塊的情況。
使用規(guī)則
在分層路由的每個級別上,我們都可以設(shè)置多個守衛(wèi)。 路由器會先按照從最深的子路由由下往上檢查的順序來檢查CanDeactivate守護條件。 然后它會按照從上到下的順序檢查CanActivate守衛(wèi)。 如果任何守衛(wèi)返回false,其它尚未完成的守衛(wèi)會被取消,這樣整個導(dǎo)航就被取消了。
CanActivate
使用CanActivate來處理導(dǎo)航路由,需要在路由配置中,添加導(dǎo)入AuthGuard類,修改管理路由并通過CanActivate屬性來引用AuthGuard。
具體的守衛(wèi)規(guī)則要看AuthGuard類的實現(xiàn)。而AuthGuard 類是需要繼承CanActivate 類的:export class AuthGuard implements CanActivate {}
import { AuthGuard } from '../auth-guard.service'; const adminRoutes: Routes = [ { path: 'admin', component: AdminComponent, canActivate: [AuthGuard], // 重點 children: [ { path: '', children: [ { path: 'crises', component: ManageCrisesComponent }, { path: 'heroes', component: ManageHeroesComponent }, { path: '', component: AdminDashboardComponent } ], } ] } ]; @NgModule({ imports: [ RouterModule.forChild(adminRoutes) ], exports: [ RouterModule ] }) export class AdminRoutingModule {}
CanActivateChild 守衛(wèi)自路由
就像我們可以通過CanActivate來守衛(wèi)路由一樣,我們也能通過CanActivateChild守衛(wèi)來保護子路由。CanActivateChild守衛(wèi)的工作方式和CanActivate守衛(wèi)很相似,不同之處在于它會在每個子路由被激活之前運行。我們保護了管理特性模塊不受未授權(quán)訪問,也同樣可以在特性模塊中保護子路由。
這個使用起來比較簡單,只需要在需要守衛(wèi)的子路由的配置上添加即可。而AuthGuard 類是需要繼承canActivateChild 類的:export class AuthGuard implements canActivateChild {}
const adminRoutes: Routes = [ { path: 'admin', component: AdminComponent, canActivate: [AuthGuard], children: [ { // 無組件路由,相當于分組 path: '', canActivateChild: [AuthGuard], // 守衛(wèi)子路由 children: [ { path: 'crises', component: ManageCrisesComponent }, { path: 'heroes', component: ManageHeroesComponent }, { path: '', component: AdminDashboardComponent } ] } ] } ];
CanDeactivate 處理未保存的更改
在現(xiàn)實世界中,我們得先把用戶的改動積累起來。 我們可能不得不進行跨字段的校驗,可能要找服務(wù)器進行校驗,可能得把這些改動保存成一種待定狀態(tài),直到用戶或者把這些改動作為一組進行確認或撤銷所有改動。
當用戶要導(dǎo)航到外面時,該怎么處理這些既沒有審核通過又沒有保存過的改動呢? 我們不能馬上離開,不在乎丟失這些改動的風險,那顯然是一種糟糕的用戶體驗。
我們應(yīng)該暫停,并讓用戶決定該怎么做。如果用戶選擇了取消,我們就留下來,并允許更多改動。如果用戶選擇了確認,那就進行保存。
在保存成功之前,我們還可以繼續(xù)推遲導(dǎo)航。如果我們讓用戶立即移到下一個界面,而保存卻失敗了(可能因為數(shù)據(jù)不符合有效性規(guī)則),我們就會丟失該錯誤的上下文環(huán)境。
在等待服務(wù)器的答復(fù)時,我們沒法阻塞它 —— 這在瀏覽器中是不可能的。 我們只能用異步的方式在等待服務(wù)器答復(fù)之前先停止導(dǎo)航。
我們需要CanDeactivate守衛(wèi)。
Resolve
主要實現(xiàn)的就是導(dǎo)航前預(yù)先加載路由信息??梢宰龅?,當真正需要導(dǎo)航進來這個詳情頁面時,是不需要再去獲取數(shù)據(jù)的。是提前加載好的。
服務(wù)可以實現(xiàn)Resolve守衛(wèi)接口來同步或異步解析路由數(shù)據(jù)。
CanLoad - 保護特性模塊的加載
前提
異步路由,只要是懶惰加載特征區(qū)域。這樣做的好處:
- 可以繼續(xù)構(gòu)建特征區(qū),但不再增加初始包大小。
- 只有在用戶請求時才加載特征區(qū)。
- 為那些只訪問應(yīng)用程序某些區(qū)域的用戶加快加載速度。
路由器用loadChildren屬性來映射我們希望惰性加載的捆文件,這里是AdminModule。
const appRoutes: Routes = [ { path: 'admin', loadChildren: 'app/admin/admin.module#AdminModule', } ];
映射到了我們以前在管理特性區(qū)構(gòu)建的admin.module.ts 文件。在文件路徑后面,我們使用# 來標記出文件路徑的末尾,并告訴路由器AdminModule 的名字。打開admin.module.ts 文件,我們就會看到它正是我們所導(dǎo)出的模塊類的名字。
export class AdminModule {}
簡介
我們已經(jīng)使CanAcitvate保護AdminModule了,它會阻止對管理特性區(qū)的匿名訪問。我們在請求時可以異步加載管理類路由,檢查用戶的訪問權(quán),如果用戶未登錄,則跳轉(zhuǎn)到登陸頁面。但更理想的是,我們只在用戶已經(jīng)登錄的情況下加載AdminModule,并且直到加載完才放行到它的路由。
我們可以用CanLoad守衛(wèi)來保證只在用戶已經(jīng)登錄并嘗試訪問管理特性區(qū)時才加載一次AdminModule。
幾個概念
無組件路由
無組件路由,不借助組件對路由進行分組。來看AdminComponent
下的子路由,我們有一個帶path和children的子路由,但它沒有使用component。這并不是配置中的失誤,而是在使用無組件路由。
const adminRoutes: Routes = [ { path: 'admin', component: AdminComponent, children: [ { // 無組件路由 path: '', children: [ { path: 'crises', component: ManageCrisesComponent }, { path: 'heroes', component: ManageHeroesComponent }, { path: '', component: AdminDashboardComponent } ] } ] } ]; @NgModule({ imports: [ RouterModule.forChild(adminRoutes) ], exports: [ RouterModule ] }) export class AdminRoutingModule {}
預(yù)加載: 在后臺加載特征區(qū)域
每次導(dǎo)航成功發(fā)生時,路由器將查看惰性加載的特征區(qū)域的配置,并根據(jù)提供的策略作出反應(yīng)。 路由器默認支持兩種預(yù)加載策略:
- 完全不預(yù)加載,這是默認值。惰性加載特征區(qū)域仍然按需加載。
- 預(yù)加載所有惰性加載的特征區(qū)域。
路由器還支持自定義預(yù)加載策略,用來精細控制預(yù)加載。
自定義預(yù)加載策略
Route Data 啟動預(yù)加載
其中有參數(shù)preload布爾值,如果它為true,就調(diào)用內(nèi)置Router
提供的load函數(shù)預(yù)主動加載這些特征模塊。
創(chuàng)建自定義策略
我們將需要實現(xiàn)抽象類PreloadingStrategy和preload方法。在異步加載特征模塊和決定是否預(yù)加載它們時,路由器調(diào)用preload方法。 preload方法有兩個參數(shù),第一個參數(shù)Route提供路由配置,第二個參數(shù)是預(yù)加載特征模塊的函數(shù)。
鏈接參數(shù)數(shù)組
鏈接參數(shù)數(shù)組保存路由導(dǎo)航時所需的成分:
- 指向目標組件的那個路由的路徑(path)
- 必備路由參數(shù)和可選路由參數(shù),它們將進入該路由的URL
e.g.我們可以把RouterLink指令綁定到一個數(shù)組,就像這樣:
<a [routerLink]="['/heroes']">Heroes</a>
e.g.在指定路由參數(shù)時,我們寫過一個雙元素的數(shù)組,就像這樣:
this.router.navigate(['/hero', hero.id]);
e.g.我們可以在對象中提供可選的路由參數(shù),就像這樣:
<a [routerLink]="['/crisis-center', { foo: 'foo' }]">Crisis Center</a>
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
AngularJS constant和value區(qū)別詳解
angularJS可以通過constant(name,value)和value(name,value)對于創(chuàng)建服務(wù)也是很重要的。他們之間有什么不同呢?今天小編給大家分享AngularJS constant和value區(qū)別詳解,需要的朋友參考下2017-02-02ui-router中使用ocLazyLoad和resolve的具體方法
這篇文章主要介紹了ui-router中使用ocLazyLoad和resolve的具體方法,詳細的介紹了ocLazyLoad和resolve的具體用法,非常具有實用價值,需要的朋友可以參考下2017-10-10如何利用@angular/cli V6.0直接開發(fā)PWA應(yīng)用詳解
這篇文章主要給大家介紹了如何利用@angular/cli V6.0直接開發(fā)PWA應(yīng)用的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習或者使用@angular/cli V6.0具有一定的參考學(xué)習價值,需要的朋友可以參考下2018-05-05Angular應(yīng)用Bootstrap過程步驟邏輯詳解
這篇文章主要為大家介紹了Angular應(yīng)用Bootstrap過程步驟邏輯詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-07-07AngularJS實現(xiàn)數(shù)據(jù)列表的增加、刪除和上移下移等功能實例
這篇文章給大家分享了AngularJS循環(huán)實現(xiàn)數(shù)據(jù)列表的增加、刪除和上移下移等基礎(chǔ)功能,對大家學(xué)習AngularJS具有一定的參考借鑒價值,有需要的朋友可以看看。2016-09-09AngularJS中控制器函數(shù)的定義與使用方法示例
這篇文章主要介紹了AngularJS中控制器函數(shù)的定義與使用方法,結(jié)合具體實例形式分析了AngularJS控制器函數(shù)的定義、綁定及相關(guān)使用技巧,需要的朋友可以參考下2017-10-10AngularJS中如何使用$http對MongoLab數(shù)據(jù)表進行增刪改查
這篇文章主要介紹了AngularJS中如何使用$http對MongoLab數(shù)據(jù)表進行增刪改查的相關(guān)資料,需要的朋友可以參考下2016-01-01深入學(xué)習AngularJS中數(shù)據(jù)的雙向綁定機制
這篇文章主要介紹了AngularJS中數(shù)據(jù)的雙向綁定機制,雙向綁定使得HTML中呈現(xiàn)的view與AngularJS中的數(shù)據(jù)一致,是Angular的重要特性之一,需要的朋友可以參考下2016-03-03Angular實現(xiàn)的簡單查詢天氣預(yù)報功能示例
這篇文章主要介紹了Angular實現(xiàn)的簡單查詢天氣預(yù)報功能,涉及AngularJS針對第三方API接口交互的相關(guān)操作技巧,需要的朋友可以參考下2017-12-12