You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 11:canActivate/child获取路由参数及路由匹配问题

Angular 11 路由权限校验问题及解决方案

问题描述

  • 问题1:针对带参数的子路由/fee-collection/reports/view/:school_id/:year_id/:date_range/:mode,页面重载时在canActivate中无法获取路由参数,但从其他组件导航到该路由时,可在canActivateChild中获取参数;
  • 问题2:需要判断实际路由(如/fee-collection/reports/view/5/6/3/2)与菜单中定义的带参数路由模板是否匹配。

相关代码

菜单配置

{
    id: "fee-collection",
    title: "Fees",
    type: "collapsable",
    icon: "heroicons_outline:currency-rupee",
    children: [
      {
        id: "View-reports_4",
        title: "View Fee Reports",
        type: "basic",
        icon: "heroicons_outline:ticket",
        link: `/fee-collection/reports/view/:school_id/:year_id/:date_range/:mode`,
        externalLink: true,
        hidden: (title: FuseNavigationItem) => true,
      }
}

路由配置(routing.ts)

{
    path: "",
    canActivate: [AuthGuard],
    canActivateChild: [AuthGuard],
    component: LayoutComponent,
    resolve: {
      initialData: InitialDataResolver,
    },
    children: [
      {
        path: "",
        loadChildren: () =>
          import("app/modules/fee-collection/fee-collection.module").then(
            (m) => m.FeeCollectionModule
          ),
      },
    ],
  },

AuthGuard代码

/**
 * Can activate
 *
 * @param route
 * @param state
 */

canActivate(
  route: ActivatedRouteSnapshot,
  state: RouterStateSnapshot
): Observable<boolean> | Promise<boolean> | boolean {
  // console.log(this._authService.isLoggedIn);
  console.log(route, "queryParams")
  this.params = route.paramMap.getAll(''); 
  console.log(state, "state")
  this._activatedroute.params.subscribe(params => {
    console.log(params,"activated routes")
  })
  
  const redirectUrl = state.url === "/sign-out" ? "/" : state.url;
  return this._check(redirectUrl);
}

解决方案

问题1:页面重载时canActivate获取路由参数的问题

页面重载时,canActivate接收的ActivatedRouteSnapshot是根路由快照,而非带参数的子路由快照。可以通过两种方式获取参数:

  1. 遍历子路由快照:
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
  let targetRoute = route;
  // 递归找到最底层的子路由节点
  while (targetRoute.children.length > 0) {
    targetRoute = targetRoute.children[0];
  }
  // 读取子路由参数
  const schoolId = targetRoute.paramMap.get('school_id');
  const yearId = targetRoute.paramMap.get('year_id');
  const dateRange = targetRoute.paramMap.get('date_range');
  const mode = targetRoute.paramMap.get('mode');
}
  1. 解析URL获取参数:
    直接从state.url解析参数,无需依赖路由快照:
import { Router } from '@angular/router';

constructor(private _router: Router) {}

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
  const urlSegments = this._router.parseUrl(state.url).root.children['primary'].segments;
  // 对应路由模板的参数位置
  const schoolId = urlSegments[3].path;
  const yearId = urlSegments[4].path;
  const dateRange = urlSegments[5].path;
  const mode = urlSegments[6].path;
}

优化建议:优先使用canActivateChild处理子路由权限校验,它会直接接收子路由的ActivatedRouteSnapshot,无需额外遍历或解析。

问题2:实际路由与菜单路由模板匹配

通过将菜单路由模板转换为正则表达式,实现路由匹配:

  1. 路由模板转正则工具函数:
function convertRouteTemplateToRegex(template: string): RegExp {
  // 将模板中的参数占位符替换为正则匹配规则
  const regexPattern = template.replace(/:\w+/g, '([^/]+)');
  // 添加首尾锚点确保完全匹配
  return new RegExp(`^${regexPattern}$`);
}
  1. 匹配并提取参数:
// 菜单中的路由模板
const menuRoute = '/fee-collection/reports/view/:school_id/:year_id/:date_range/:mode';
// 实际访问的路由
const actualRoute = '/fee-collection/reports/view/5/6/3/2';

const routeRegex = convertRouteTemplateToRegex(menuRoute);
const isMatched = routeRegex.test(actualRoute); // 返回true

// 提取参数
const matchResult = actualRoute.match(routeRegex);
if (matchResult) {
  const [_, schoolId, yearId, dateRange, mode] = matchResult;
  // 使用提取到的参数做后续处理
}

如果需要批量匹配菜单中的所有路由模板,可遍历菜单配置数组,逐个执行上述匹配逻辑。

内容的提问来源于stack exchange,提问作者Jayanthi T

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 03:43:16