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

    决定自己的高度的是你的态度,而不是你的才能

    记得我们是终身初学者和学习者

    总有一天我也能成为大佬

  • 相关阅读:
    字典的两种访问方式
    python列表
    字符串基础操作
    C#解leetcode 11. Container With Most Water
    c# hasvalue属性
    C#解leetcode 238. Product of Array Except Self
    win7/win8 64位系统注册TeeChart8.ocx 控件---以及dllregisterserver调用失败问题解决办法
    C#解leetcode 219. Contains Duplicate II
    转载:C# HashSet 用法
    C#解leetcode:119. Pascal's Triangle II
  • 原文地址:https://www.cnblogs.com/fangdongdemao/p/14295975.html
Copyright © 2020-2023  润新知