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是根路由快照,而非带参数的子路由快照。可以通过两种方式获取参数:
- 遍历子路由快照:
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'); }
- 解析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:实际路由与菜单路由模板匹配
通过将菜单路由模板转换为正则表达式,实现路由匹配:
- 路由模板转正则工具函数:
function convertRouteTemplateToRegex(template: string): RegExp { // 将模板中的参数占位符替换为正则匹配规则 const regexPattern = template.replace(/:\w+/g, '([^/]+)'); // 添加首尾锚点确保完全匹配 return new RegExp(`^${regexPattern}$`); }
- 匹配并提取参数:
// 菜单中的路由模板 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
相关产品推荐
相关产品推荐

