1. 程式人生 > >Angular學習筆記(五)之輔助路由和路由守衛

Angular學習筆記(五)之輔助路由和路由守衛

輔助路由

啟用後,在任何頁面都會顯示相關的輔助路由元件。

輔助路由的語法分3步

1.頁面插座,輔助路由的寫法是帶有name屬性

<router-outlet></router-outlet>
<router-outlet name="aux"></router-outlet>

2.路徑配置,名為aux的輔助路由可以用來顯示xxx元件和yyy元件

{path:'xxx',component:XxxComponent,outlet:'aux'},
{path:'yyy',component:YyyComponent,outlet:'aux'
}

3.路由引數跳轉路由,primary控制主路由,不管在哪個頁面,點選後主路由都會顯示home元件

<a [routerLink]="[{outlets:{primary:'home',aux:'xxx'}}]">開始諮詢</a>

主路由-輔助路由。路由的配置:名為aux的輔助路由可以顯示xxx和yyy元件。點選Xxx時,主路由顯示home元件,輔助路由顯示xxx元件

一個輔助路由demo:

//app.component.html

<a [routerLink]="[{outlets:{primary:'home',aux:'consult'}}]"
>
開始諮詢</a> <!-- <a (click)="aux()">開始諮詢(這是另一種跳轉方式)</a> --> <a [routerLink]="[{outlets:{aux:null}}]">停止諮詢</a> <router-outlet></router-outlet> <router-outlet name="aux"></router-outlet>
//routes
{path:'consult',component:ConsultComponent,outlet:'aux'
}

使用router跳轉的寫法

//app.component.ts
  aux(){
    this.router.navigate([{outlets:{primary:'home',aux:'consult'}}]);
  }

路由守衛

也就是,攔截器,在進入或離開路由前執行一些邏輯

  • CanActivate : 處理導航到某路由之前的情況,如:付費使用者
  • CanDeactivate : 處理從當前路由離開的情況,如:是否未儲存就離開
  • Resolve : 在路由啟用之前獲取路由資料,提高使用者體驗

路由守衛語法:

CanActivate

一個用來定義類的介面,路由器會首先呼叫它來決定是否應該啟用該元件。應該返回布林值或能解析為布林值的可觀察物件(Observable)或承諾(Promise)。

 class CanActivateGuard implements CanActivate {
    canActivate(
      route: ActivatedRouteSnapshot,
      state: RouterStateSnapshot
    ): Observable<boolean>|Promise<boolean>|boolean { ... }
}

{ path: ..., canActivate: [CanActivateGuard] }

返回布林值為true時進入路由

canActivate demo

//1.編寫CanActivate守衛PermissionGuard
// 在guard/permission.guard.ts中

//匯入CanActivate守衛
import { CanActivate } from '@angular/router';

export class PermissionGuard implements CanActivate {
    canActivate(){
        var hasPermission:boolean = Math.random() > 0.5;
        if (!hasPermission) {
            console.log('使用者無許可權訪問');
        };
        return hasPermission;
        //返回值true時進入路由
    }
}

//2.在路由配置中增加canActivate屬性
// 在app-routing.module.ts中

//匯入PermissionGuard
import { PermissionGuard } from './guard/permission.guard';

const routes: Routes = [{path:'stocks/:id',component:StocksComponent,canActivate:[PermissionGuard]}]

//3.寫入providers
// 在app.module.ts中
//先匯入
import { PermissionGuard } from './guard/permission.guard';

providers: [PermissionGuard]

Tips : CanActivate在引入介面時首字母大寫,其他都是首字母小寫canActivate

CanDeactivate

一個用來定義類的介面,路由器在導航後會首先呼叫它來決定是否應該取消該元件的啟用狀態。應該返回布林值或能解析為布林值的可觀察物件(Observable)或承諾(Promise)。

class CanDeactivateGuard implements CanDeactivate<T> {
    canDeactivate(
      component: T,
      route: ActivatedRouteSnapshot,
      state: RouterStateSnapshot
    ): Observable<boolean>|Promise<boolean>|boolean { ... }
}

{ path: ..., canDeactivate: [CanDeactivateGuard] }

返回布林值為true時離開路由

CanDeactivate demo

//1.編寫CanDeactivate守衛focusGuard
// 在guard/permission.guard.ts中

//匯入CanDeactivate守衛和要離開的元件
import { CanDeactivate } from '@angular/router';
import { StocksComponent } from '../stocks/stocks.component';

//判斷component上isfocus是否已關注,未關注就彈出視窗 
export class focusGuard implements CanDeactivate<StocksComponent> {
    canDeactivate(component:StocksComponent){
        if(!component.isfocus){
            return window.confirm('不關注嗎')
        }else{
            return true;
        }
    }
}


//2.在stocks.component.html (要守衛的元件)上寫按鈕
<button (click)="focus()">關注</button>

//3.在stocks.component.ts 寫邏輯
  focus(){
    this.isfocus = true;
  }

//4.在路由配置中增加canDeactivate屬性
// 在app-routing.module.ts中

//5.匯入focusGuard
import { focusGuard } from './guard/focus.guard';

const routes: Routes = [{path:'stocks/:id',component:StocksComponent,canActivate:[PermissionGuard],canDeactivate:[focusGuard]}]

//6.寫入providers
// 在app.module.ts中

//先匯入
import { focusGuard } from './guard/focus.guard';

providers: [PermissionGuard,focusGuard]

Resolve

一個用來定義類的介面,路由器會在渲染該路由之前先呼叫它來解析路由資料。應該返回一個值或能解析為值的可觀察物件(Observable)或承諾(Promise)。

class ResolveGuard implements Resolve<T> {
    resolve(
      route: ActivatedRouteSnapshot,
      state: RouterStateSnapshot
    ): Observable<any>|Promise<any>|any { ... }
}

{ path: ..., resolve: [ResolveGuard] }

將返回的資料帶入路由

Resolve demo

在進入路由{path:”stock/:id”}時,當id=1時,例項化stock類

//1.在stockComponent中編寫stock類的建構函式
export class StocksComponent implements OnInit {

  private stock:Stock;

  constructor() { }

  ngOnInit() {
  }
}
export class Stock{
  constructor(public id:number,public name:string){}
}
//2.編寫Resolve:stockResolve,返回值將傳入對應path的Resolve屬性中,當id=1時,例項化stock並返回

//注意匯入的內容
import { Resolve,ActivatedRouteSnapshot,RouterStateSnapshot,Router } from '@angular/router';
import { Stock } from '../stocks/stocks.component';
import { Observable } from 'rxjs';
import { Injectable } from '@angular/core';

//@Injectable() 使constructor中的依賴注入生效,元件有@Component註解所以不用寫@Injectable()

@Injectable()
export class stockResolve implements Resolve<Stock>{

    constructor(private router:Router){}

    resolve(route: ActivatedRouteSnapshot,state: RouterStateSnapshot): Observable<Stock>|Promise<Stock>|Stock {
        let id = route.params['id'];
        //路由路徑id為1時
        if(id == 1){
            console.log('這裡是1');
            return new Stock(1,'IBM'); // 返回例項化值 stock
        }else{
            this.router.navigate(['/home']);
            return undefined;
        }
    }
}
//3.在路由配置中,path路徑中增加Resolve屬性:
{path:'stocks/:id',component:StocksComponent,canActivate:[PermissionGuard],canDeactivate:[focusGuard],resolve:{stock:stockResolve}
    //resolve物件格式,各種資料。stockResolve守衛傳值給stock
}

//4.在stockComponent中的ngOnInit,data資料值來源於path中的stock,stock是Stock型別
ngOnInit() {
    this.routerInfo.data.subscribe((data:{stock:Stock})=>{
      this.stock = data.stock
      console.log(this.stock);
    });
  }
//5.在provider中寫入stockResolve 
//先匯入
import { stockResolve } from './guard/stock.resolve';

providers: [PermissionGuard,focusGuard,stockResolve ]

Tips:注意Resolve的匯入內容和依賴注入時需使用@Injectable()

你的負擔將變成禮物,你受的苦將照亮你的路。 ——泰戈爾