MST
星途 面试题库

面试题:Angular路由守卫中不同守卫的执行顺序探究

Angular中有多种路由守卫,如CanActivate、CanActivateChild、CanDeactivate、Resolve等。请详细说明这些路由守卫在路由导航过程中的执行顺序,并解释每个守卫在这个过程中的具体作用,同时举例说明在复杂路由结构下,如何利用这些守卫确保路由的正确导航和数据的合理加载。
26.8万 热度难度
前端开发Angular

知识考点

AI 面试

面试题答案

一键面试

路由守卫执行顺序

  1. CanActivate:在进入路由之前触发,用于判断是否可以激活该路由。如果所有CanActivate守卫都返回true,则继续导航,否则导航被阻止。
  2. CanActivateChild:在进入子路由之前触发,用于判断是否可以激活子路由。同样,若所有CanActivateChild守卫都返回true,才允许进入子路由。
  3. Resolve:在路由激活之前触发,用于在路由激活前获取或解析数据。例如,在显示产品详情页之前,通过Resolve提前获取产品数据。
  4. CanDeactivate:在离开当前路由时触发,用于判断是否可以离开当前路由。比如,当用户在表单中输入未保存的数据时,可通过此守卫提示用户是否保存。

各守卫具体作用

  1. CanActivate
    • 作用:决定是否允许导航到某个路由。常用于权限验证,例如只有登录用户才能访问特定页面。
    • 示例
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { AuthService } from './auth.service';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  constructor(private authService: AuthService, private router: Router) {}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): boolean {
    if (this.authService.isLoggedIn()) {
      return true;
    } else {
      this.router.navigate(['/login']);
      return false;
    }
  }
}
  1. CanActivateChild
    • 作用:与CanActivate类似,但作用于子路由。当导航到子路由时,会触发此守卫。
    • 示例:假设存在管理模块的子路由,只有管理员角色能访问。
import { Injectable } from '@angular/core';
import { CanActivateChild, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { AuthService } from './auth.service';

@Injectable({
  providedIn: 'root'
})
export class AdminGuard implements CanActivateChild {
  constructor(private authService: AuthService, private router: Router) {}

  canActivateChild(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): boolean {
    if (this.authService.isAdmin()) {
      return true;
    } else {
      this.router.navigate(['/home']);
      return false;
    }
  }
}
  1. Resolve
    • 作用:在路由激活前解析数据,确保组件在渲染前能获取到所需数据。这样可避免组件加载后再异步获取数据导致的闪烁等问题。
    • 示例:在显示用户详情页时,提前获取用户数据。
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { UserService } from './user.service';

@Injectable({
  providedIn: 'root'
})
export class UserResolver implements Resolve<any> {
  constructor(private userService: UserService) {}

  resolve(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot) {
    return this.userService.getUser(route.params['id']);
  }
}
  1. CanDeactivate
    • 作用:在离开当前路由时进行确认,常用于防止用户意外离开未保存数据的页面。
    • 示例:当用户在编辑文章页面未保存文章就尝试离开时,提示用户。
import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { ArticleEditComponent } from './article - edit.component';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class ArticleEditGuard implements CanDeactivate<ArticleEditComponent> {
  canDeactivate(
    component: ArticleEditComponent,
    currentRoute: ActivatedRouteSnapshot,
    currentState: RouterStateSnapshot,
    nextState?: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    return component.canLeave();
  }
}

在复杂路由结构下的应用

假设应用有多层嵌套路由,如/admin/dashboard/user/:id

  1. 权限验证:使用CanActivate在/admin路由级别验证用户是否为管理员,在/admin/dashboard使用CanActivateChild进一步验证权限。
  2. 数据加载:在/admin/dashboard/user/:id路由使用Resolve提前获取用户详细数据,确保UserDetailComponent能直接使用数据渲染。
  3. 防止意外离开:若UserDetailComponent有可编辑区域,在用户离开时,通过CanDeactivate提示用户保存更改。

通过合理组合这些路由守卫,能确保复杂路由结构下导航的正确性和数据加载的合理性。