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
相关文章
相关标签/搜索