路由知識(shí)總結(jié)
可以把SPA(single page
application)理解為是一個(gè)視圖狀態(tài)的集合。Angular架構(gòu)下的各個(gè)視圖會(huì)因?yàn)椴僮鞯牟煌@示的也會(huì)各有千秋,這些功勞全都得歸功于路由。
基礎(chǔ)知識(shí)
路由相關(guān)的對(duì)象總結(jié):
1.Routes:路由配置,表示在哪個(gè)URL中會(huì)顯示哪個(gè)組件,還有就是在哪個(gè)RouterOutlet(像是一個(gè)插排一樣)中顯示組件。
/** * Tips: path 不能使用斜杠進(jìn)行開頭,因?yàn)榭梢宰孉ngular自動(dòng)使用絕對(duì)路徑和相對(duì)路徑。 *
配置好路徑以及路徑對(duì)應(yīng)的需要顯示的component。 */ const routes: Routes = [ {path: '', component:
HomeComponent}, {path: 'products', component: ProductsComponent} ];
2.RouterOutlet:在HTML標(biāo)記路由內(nèi)的占位符指令。
<router-outlet></router-outlet>
3.Router:在運(yùn)行時(shí)指定路由的行為,通過navigate()以及navigateByURL()指定路由到哪個(gè)路由中去。
//html模版上寫入一個(gè)點(diǎn)擊事件,通過事件,觸發(fā)clickProductButton事件。通過router實(shí)現(xiàn)路由。 constructor(
private router: Router ) {} public clickProductButton() {
this.router.navigate(['/products']); }
4.RouterLink
:在HTML中聲明路由導(dǎo)航用的指令。與Router相類似,只不過Router是在controller中使用的,而RouterLink在HTML中使用的。
<!--必須加入斜杠,因?yàn)檫@樣才能區(qū)分是跟路由,還是子路由--> <!--為什么 routerLink的值是一個(gè)數(shù)組呢,因?yàn)榭梢酝ㄟ^路由傳入一些參數(shù)-->
<a [routerLink]="['/']">主頁</a> <a [routerLink]="['/products']">商品詳情</a>
5.ActivatedRoute:當(dāng)前激活路由的相關(guān)信息,可以被這個(gè)類記錄,并且被我們使用。
如何在路由中傳遞數(shù)據(jù)
1.在查詢參數(shù)中傳遞數(shù)據(jù)
多添加一個(gè)[queryParams]的屬性綁定形如:
<a [routerLink]="['/products']" [queryParams]= "{id:1}">商品詳情</a>
獲?。和ㄟ^ActivatedRoute.queryParams[參數(shù)的key]
2.在路由路徑中傳遞數(shù)據(jù)
* 修改Routes中的path屬性,形如:path:'product/:type'
* routerLink中多添加一個(gè)參數(shù),形如:[routerLink]="['/products','book']"
,這里的book就是給我們剛剛定義type的值。
獲?。和ㄟ^ ActivatedRoute.params[參數(shù)的key]
3.在路由配置中傳遞數(shù)據(jù)
通過在Routes中定義data參數(shù) 形如:
{path: '', component: HomeComponent, data: [{key: value}]}
然后通過ActivatedRoute.data[0] [key] 來獲取
Tips:參數(shù)快照與參數(shù)訂閱
首先上代碼:
//參數(shù)訂閱 this.activatedRoute.params.subscribe((params: Params) => {
this.productType = params['type']; }); //參數(shù)快照 this.productType =
this.activatedRoute.snapshot.params['type'];
他倆的區(qū)別就在于我們現(xiàn)在有兩個(gè)不同的按鈕,跳轉(zhuǎn)到的URL分別為
[routerLink]="['/products','book']",和[routerLink]="['/products','watch']",可以看出它們只有type的參數(shù)類型不同。
如果使用了快照,點(diǎn)擊了第一個(gè)按鈕,在點(diǎn)擊第二個(gè),那么獲取到的參數(shù)不會(huì)發(fā)生變化,這個(gè)時(shí)候我們就應(yīng)該使用參數(shù)訂閱(觀察者模式的思想,感興趣的可以查詢RXJS,進(jìn)行詳細(xì)了解)。
重定向路由
在Routes中添加 對(duì)應(yīng)參數(shù):
{path: '', redirectTo: '/home', pathMatch: 'full'}
子路由
在正常的情況下,組件與組件之間一定是會(huì)有嵌套關(guān)系的,這種嵌套關(guān)系就會(huì)導(dǎo)致我們的路由插座()同樣也是嵌套的。子路由就是為了解決路由插座父子嵌套關(guān)系的
使用子路由的步驟:
1.修改在Routes中,product的路由信息,主要就是添加了一個(gè)children屬性:
{path: 'products/:type', component: ProductsComponent, children: [ {path: '',
component: ProductDescComponent}, {path: 'seller/:id', component:
SellerComponent} ]}
2.在需要子路由的html中,插上 作為插座
3.然后在需要跳轉(zhuǎn)的地方編寫如下代碼
<a [routerLink] = "['./']">跳轉(zhuǎn)到商品詳情</a> <a [routerLink] = "['./seller',
99]">跳轉(zhuǎn)到售貨員信息</a>
輔助路由
剛剛的子路由如果說是父子關(guān)系的話,那么輔助路由就是"兄弟關(guān)系了"。
這種場景出現(xiàn)在我們?cè)谝粋€(gè)界面中,兩個(gè)component分別被不同的路由機(jī)制管理著,如果只使用原來的插槽,沒有辦法指定用的到底是哪一種路由策略,所以輔助路由就這么誕生了。
使用輔助路由的步驟:
1.> 通過name 指定具體的路由插座名稱
2.> 指定當(dāng)前這個(gè)aux路由可以展示哪些component。
{path: /xxx, component: XxxComponent, outlet: aux}
{path: /yyy, component: YyyComponent, outlet: aux}
3.> 在進(jìn)行導(dǎo)航的地方指定我們需要的那個(gè)路由
<>
<>
路由守衛(wèi)
頁面從一種頁面狀態(tài)跳轉(zhuǎn)到另一種頁面狀態(tài),有的時(shí)候需要一些條件,檢查這些條件就是路由守衛(wèi)的職責(zé)。
一共可以分為三種:
1.CanActivate: 處理導(dǎo)航到某路由的情況
大概的使用步驟:
首先我們先要寫一個(gè)守衛(wèi)的類:
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from
"@angular/router"; /** * 這個(gè)路由守衛(wèi)用于實(shí)現(xiàn)進(jìn)入某以頁面需要滿足某些需求的情況。 */ export class
LoginGuard implements CanActivate { private flag = true; canActivate(route:
ActivatedRouteSnapshot, state: RouterStateSnapshot) {
//這里給了一個(gè)隨機(jī)數(shù),如果數(shù)字大于0.5則可以進(jìn)行登陸,否則會(huì)被攔截 this.flag = Math.random() > 0.5; if (
this.flag ) { console.log('可以登陸'); } console.log(this.flag); return this.flag;
} }
然后將守衛(wèi)的類添加到Routes中需要守衛(wèi)的規(guī)則中:
{path: 'products/:type', component: ProductsComponent, canActivate:
[LoginGuard], children: [ {path: '', component: ProductDescComponent}, {path:
'seller/:id', component: SellerComponent} ]}
最后在app.module.ts中添加自己需要依賴注入的守衛(wèi)類即可:
providers: [LoginGuard]
2.CanDeactive: 處理從當(dāng)前路由離開的情況
大概的使用步驟:
首先我們先要寫一個(gè)守衛(wèi)的類:
import { CanDeactivate, ActivatedRouteSnapshot } from "@angular/router";
import { ProductsComponent } from "../products/products.component"; export
class NotSaveGuard implements CanDeactivate<ProductsComponent> { private flag =
true; canDeactivate(component: ProductsComponent, _currentRoute:
ActivatedRouteSnapshot) { //這里暫時(shí)給出一個(gè)提示框 return window.confirm("還沒有保存確定離開嗎?"); }
}
然后將守衛(wèi)的類添加到Routes中需要守衛(wèi)的規(guī)則中:
{path: 'products/:type', component: ProductsComponent, canDeActivate:
[NotSaveGuard], children: [ {path: '', component: ProductDescComponent}, {path:
'seller/:id', component: SellerComponent} ]}
最后在app.module.ts中添加自己需要依賴注入的守衛(wèi)類即可:
providers: [NotSaveGuard]
3.Resolve:在路由激活之前獲取數(shù)據(jù)
在進(jìn)入路由之前檢測數(shù)據(jù)是不是已經(jīng)存在,以為網(wǎng)絡(luò)請(qǐng)求具有延遲,如果出現(xiàn)了,已經(jīng)路由到下個(gè)界面,但是信息還沒有存在的情況,我們就會(huì)讓界面路由到錯(cuò)誤界面或者別的什么界面。
大概的使用步驟:
1.首先我們定義一個(gè)Resolve守衛(wèi)的類:
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from
"@angular/router"; import { ProductsComponent, Product } from
"../products/products.component"; import { Injectable } from "@angular/core";
@Injectable() export class ProductGuard implements Resolve<Product> {
constructor(private router: Router) { } resolve(route: ActivatedRouteSnapshot,
state: RouterStateSnapshot) { if (route.params['type'] === 'book') { return new
Product(1, 'iphone X'); } else { this.router.navigate(['/home']); return
undefined; } } }
2.然后將resolve屬性添加到守衛(wèi)的規(guī)則中
{path: 'products/:type', component: ProductsComponent, resolve: {product:
ProductGuard}, children: [ {path: '', component: ProductDescComponent}, {path:
'seller/:id', component: SellerComponent} ]}
3.依賴注入 ProductGuard
providers: [ProductGuard]
4.resolve 其實(shí)相當(dāng)于對(duì)返回值的一種增強(qiáng),接受返回值的地方我們應(yīng)該這么寫
this.activatedRoute.data.subscribe((data: {product: Product}) => {
//注意:這里之所以可以使用data.product,是因?yàn)槲覀冊(cè)赗outes路由中配置的 resolve: {product:
ProductGuard}所致。這里的product就是返回值的名字,如果變化了,兩個(gè)名字都要一起變化。 this.productId =
data.product.id; this.productName = data.product.name; });
最后附加上本文提及到的代碼,我已經(jīng)放在github上,可供參考
https://github.com/luckypoison/Augular4Route
<https://yq.aliyun.com/go/articleRenderRedirect?url=https%3A%2F%2Fgithub.com%2Fluckypoison%2FAugular4Route>
熱門工具 換一換