angular11源碼探索二十二[路由Route下路由守衛]

路由守衛

canActivate

用於肯定是否能夠激活路由。若是全部守衛都返回true,導航將繼續。若是有任何後衛返回false,導航將被取消。異步

CanActivateChild

類能夠實現爲肯定是否能夠激活子路由的後衛的接口。若是全部守衛都返回true,導航將繼續。若是有任何後衛返回false,導航將被取消。若是任何防禦返回a UrlTree,則當前導航被取消,而且新的導航開始UrlTree從防禦返回。函數

{
      path: 'a', component: AComponent, data: {name: 'xxx'},
      canActivate: [OneService],
      canActivateChild:[OneService],
      children: [
        {path:'c/d', component: CComponent}
      ]
    },
        
export class OneService implements CanActivate, CanActivateChild {

  constructor() {}
  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot)
    : Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    // route 當前快照
    console.log(route);
    // 當前的url
    // console.log(state.url);
    return true;
  }

  canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
      // childRoute  路由的子快照
    console.log(childRoute);
    return true;
  }
}

canload 防止異步守衛

**canActivate**存在這種狀況是爲了防止未經受權的用戶訪問路由,而**canLoad**用於防止應用程序在未經受權的狀況下以延遲方式(延遲加載)加載整個模塊或組件this

{path: 'home', loadChildren: () =>
 	import('./three/three.module').then(m => m.ThreeModule), 
     canLoad: [TestService]
 },
     
@Injectable()
export class TestService implements Resolve<any>,CanActivate,CanDeactivate<any>,CanLoad{
  canDeactivate(component: any, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState?: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    return of(true)
  }

canload 和canActivate之間的區別

觸發順序:url

-canload 加載code

-canActivate 進入(重要)component

這兩種不是寫在一塊兒,因此順序應該不能一律而論router

canActivateChild 進入子路由blog

canDeactivate 離開(重要)接口

canActivate 用於防止未經受權的用戶訪問某些路由three

canLoad 用於防止應用程序(延遲加載)整個模塊

resolve(解決守衛)

保證了數據獲取後在進行路由跳轉,防止由於數據延遲而出現的空組件狀況

簡單的理解成解決延遲守衛

{
            path: 'b', component: BComponent,
            resolve: {sex: TestService}
          },
=====
    
@Injectable()
export class TestService implements Resolve<any>{
  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | Promise<any> | any {
    return of([1,2,3])
  }
}
=====
export class BComponent implements OnInit, AfterViewInit {
  constructor(
              private route:ActivatedRoute
  ) {
    this.route.data.subscribe(console.log);
    // {sex: [1, 2, 3]}
  }    
}

路由防禦策略

先上源碼

function shouldRunGuardsAndResolvers(
    curr: ActivatedRouteSnapshot, future: ActivatedRouteSnapshot,
    mode: RunGuardsAndResolvers|undefined): boolean {
  if (typeof mode === 'function') {
    return mode(curr, future);
  }
  switch (mode) {
    case 'pathParamsChange':
      return !equalPath(curr.url, future.url);

    case 'pathParamsOrQueryParamsChange':
      return !equalPath(curr.url, future.url) ||
          !shallowEqual(curr.queryParams, future.queryParams);

    case 'always':
      return true;

    case 'paramsOrQueryParamsChange':
      return !equalParamsAndUrlSegments(curr, future) ||
          !shallowEqual(curr.queryParams, future.queryParams);

    case 'paramsChange':
    default:
      return !equalParamsAndUrlSegments(curr, future);
  }
}

export type RunGuardsAndResolvers =   'pathParamsChange'|'pathParamsOrQueryParamsChange'|'paramsChange'|'paramsOrQueryParamsChange'|
    'always'|((from: ActivatedRouteSnapshot, to: ActivatedRouteSnapshot) => boolean);
最後一個是自定義函數,返回boolean,用來判斷是否促發守衛

runGuardsAndResolvers的選項,默認paramsChange 模式

意味着他將從新運行路徑或路徑參數的變化,會觸發變動

變動: 意思是會觸發路由守衛

{
    path: 'home/:id',
    component: HomeComponent,
    ...
    runGuardsAndResolvers: 'paramsChange'
  }

執行
/home/1 => /home/2
/home/1 => /home/1;param1=38
/home/1;param1=38 => /home/1;param1=20
不執行
/home/1 => /home/1?queryParam=hi

爲了方便理解,我寫一個小案例

{
      path: 'a', component: AComponent,
      children: [
        {
          path: 'c/:id', component: CComponent, canActivate: [OneService],
        }
      ]
    },
====        
export class OneService implements CanActivate, CanActivateChild {

  constructor() {
  }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot)
    : Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    // route 當前快照
    console.log('觸發');
    // 當前的url
    // console.log(state.url);
    return true;
  }
} 
====
<a routerLink="/home/a/c/1">c/1</a> <br>
<a routerLink="/home/a/c/2">c/2</a> <br>
<a routerLink="/home/a/c/3">c/3</a> <br>
<a routerLink="/home/a/c/3" [queryParams]="{name:'xxx'}">c/3?name=xxx</a> <br>
<a routerLink="/home/a/c/3" [queryParams]="{name:'bbb'}">c/3?name=bbb</a> <br>
<a routerLink="/home/a/c/3" [queryParams]="{name:'ccc'}">c/3?name=ccc</a> <br>

咱們會發現問號傳參的,默認路由防禦策略不會執行路由守衛

參數

  • paramsChange :當路徑或矩陣參數(;name=ccc)改變時,忽略查詢參數更改
  • paramsOrQueryParamsChange : 任何參數更改時。這包括路徑,矩陣和查詢參數。
  • always : 設置爲「始終」時,它們將在每次導航中運行
  • pathParamsChange : 將忽略矩陣參數或查詢參數的更改,並在路徑或路徑參數更改時從新運行
  • 函數: 自定義觸發,返回boolean
相關文章
相關標籤/搜索