angular11源码探索二十二[路由Route下路由守卫]

路由守卫

如果类似于


	 //当前的导航并开始一个新的
     //路由器将自动取消,因为重定向一个新路由,也不一定非要返回false
 this.router.navigateByUrl('/home/d')
providers:[  // 添加到路由上的守卫
    {
    provide:'can1',
    useValue:(route: ActivatedRouteSnapshot, state: RouterStateSnapshot)=>{
      return false
    }
  ]

 this.router.navigateByUrl('/home/d/c;p=1').then(v=>{
      console.log(v); // 当否是成功激活的时候返回true/false
    })

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**用于防止应用程序在未经授权的情况下以延迟方式(延迟加载)加载整个模块或组件

 {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 只会触发一次

 { path: 'hello',
   loadChildren: () => import('./five/five.module').then(m => m.FiveModule),
   canLoad:['con1'] 
 },
  
  providers: [
    {provide:'con1',
      useValue: (a: ActivatedRouteSnapshot, s: RouterStateSnapshot)
        => {
        console.log(1111);
        return true
      }
    }
  ],
 我们发现因为默认是没有执行的,所以只执行一次     

通过我们发现这么模块也是只第一次的时候创建,所以慢慢就理解了constructor 的用处了吧

我们发现当拦截者第一次进入的时候才会执行,第二次就不会执行啦
模块
export class TwoRoutingModule implements OnInit{
  constructor() {
    console.log('xxx');
  }
}

canload 和canActivate之间的区别

触发顺序:

-canload 加载

-canActivate 进入(重要)

这两种不是写在一起,所以顺序应该不能一概而论

canActivateChild 进入子路由

canDeactivate 离开(重要)

canActivate 用于防止未经授权的用户访问某些路由

canLoad 用于防止应用程序(延迟加载)整个模块

传参

参数依赖注入令牌数组

竟然可以这样用

模块中
@NgModule({
  ...
  providers: [
    {
      provide: 'CanActivate1',
      useValue: (a: ActivatedRouteSnapshot, b: RouterStateSnapshot) => {
        return of(false)
      }
    },
    {
       provide: 'CanActivate2',
       useValue: (a: ActivatedRouteSnapshot, b: RouterStateSnapshot) => {
           if (a.params['id'] === '22') {
                  return Promise.resolve(true);
           } else {
                  return Promise.resolve(false);
           }
      }
    },    
    // 跳转到新路由,为什么多包一层,因为避免调用的时候默认调用
    {
      provide:'can2',
      useFactory:(router:Router)=>()=>{
        console.log(router.url);
        router.navigateByUrl('/home/d/1')
        return false;
      },
      deps:[Router]
    },  
    // 返回UrlTree类型,跳转到新路由
    {
      provide:'can3',
      useFactory:(router:Router)=>()=>{
        console.log(router.url);
       return router.parseUrl('/home/d/1')
      },
      deps:[Router]
    }
  ]
})
路由拦截
const routes: Routes = [{
  path: '', component: OneComponent, children: [
    {path: 'a', component: AComponent,
      canActivate:['CanActivate1']// 竟然可以这样写,学习到了
    },
  ]
}];

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]}
  }    
}    

路由防护策略

先上源码

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>  

我们会发现问号传参的,默认路由防护策略不会执行路由守卫

paramsOrQueryParamsChange

任何参数更改时。这包括路径,矩阵和查询参数。那么什么参数发生变化,不会引起参数的变化

改变矩阵参数不会导致触发防护

上代码(多出口的切换)

  {
      path: 'd', component: DComponent,
      runGuardsAndResolvers:'paramsOrQueryParamsChange',
      canActivate:['can3'],
      children:[
        {path: 'c', component: CComponent,},
        {path: 'a', component: AComponent,outlet:'right'},

      ]
    },
        
    // 测试守卫拦截
    {
      provide:'can3',
      useFactory:(router:Router)=>()=>{
        console.log(1);
        return true
      },
      deps:[Router]
    }    
我们写两个方法让他们切换,我们发现当点击第一个会触发,切换到第二个不会触发
  backs() {
    this.router.navigateByUrl('/home/d/c')
  }
  clickMethod() {
    this.router.navigateByUrl('/home/d/(c//right:a)')
  }
========
     this.router.navigateByUrl('/home/d/c;p=1')
    this.router.navigateByUrl('/home/d/c;p=2')

总结参数

  • paramsChange :当路径修改忽略查询参数更改,忽略新出口的更改

  • pathParamsChange : 将忽略矩阵参数或查询参数或新出口的更改或者#号,并在路径或路径参数更改时重新运行,父路由参数的更改,也会触发(父路由应该算路径或路径参数)

  • paramsOrQueryParamsChange : 在原来的基础上加了查询参数和#。,忽略新出口的更改,忽略改变矩阵参数更改

  • always : 设置为“始终”时,它们将在每次导航中运行

  • 函数: 自定义触发,返回boolean

    paramsChange  
    	默认忽略查询参数更改,忽略新出口的更改,忽略描点,忽略多入口
        /a
    	改变
        /a;p=1
    	/a;p=2
    pathParamsChange  原来的基础上忽略最后的矩阵参数
    	不变
        	/a;p=1
    		/a;p=2
    	变化
        	/d/1;dd=11/e/2;dd=22
    		/d/1;dd=11/e/3;ee=22
    		内部的矩阵参数还是检测到变化的
            
    paramsOrQueryParamsChange  查询参数和描点修改会触发
    	修改
        /a;p=1
        /a;p=2
        /a;p=2?q=1
    
    pathParamsOrQueryParamsChange 忽略矩阵的修改,检测问号传参
     	不会
    		/a;p=1
        	/a;p=2
        会
        	/a;p=2?q=1
        
    always   修改始终触发
    自定义函数触发
    runGuardsAndResolvers:(from: ActivatedRouteSnapshot, to: ActivatedRouteSnapshot)=>{
            console.log(from, to);
            return true;
    },
    

空路由后面没有子路由

{
               path: 'team/:id',
               component: TeamCmp,
               children: [
                   // 正确使用方式  pathMatch: 'full'
                 {path: '', pathMatch: 'full', component: SimpleCmp},
                 {path: 'user/:name', component: UserCmp, canDeactivate: ['CanDeactivateUser']}
               ]
             }

posted @ 2021-01-19 00:45  猫神甜辣酱  阅读(425)  评论(0编辑  收藏  举报