如何复用canActivate/canChildActivate逻辑控制路由锚点元素的显示隐藏?
问题描述
我有如下Angular路由配置:
export const routes: Routes =[ { path: '', component: DefaultLayoutComponent, canActivate: [AuthGuard], canActivateChild: [AuthGuard], children: [ { path: 'dashboard', component: DashboardComponent }, { path: 'admin-only', component: AdminOnlyComponent, data: { authorize: (c: any) => c.role == "Admin" } }, { path: 'admin-or-teacher', component: AdminOrTeacherComponent, data: { authorize: (c: any) => c.role == "Admin" || c.role == "Teacher" } } ]
在AuthGuard中,我通过执行authorize方法来决定是否激活路由,目前该逻辑运行正常。
现在在Dashboard组件中有如下导航链接:
<ul class="nav flex-column w-100 px-3"> <li class="nav-item"> <a class="nav-link" routerLink="/admin-only">Admin Only</a> </li> <li class="nav-item"> <a class="nav-link" routerLink="/admin-or-teacher">Admin Or Teacher</a> </li> </ul>
我希望复用同一个authorize回调函数,根据用户权限隐藏这些链接,请问该如何实现?
实现步骤
1. 封装权限判断服务
把AuthGuard里的权限判断逻辑抽成共享服务,方便组件复用:
import { Injectable } from '@angular/core'; import { Router, ActivatedRouteSnapshot, Routes } from '@angular/router'; @Injectable({ providedIn: 'root' }) export class PermissionService { // 替换成你实际获取当前用户的方式(比如从AuthService、localStorage等) getCurrentUser() { return JSON.parse(localStorage.getItem('currentUser') || '{}'); } // 直接用路由快照的authorize回调判断权限 hasPermission(route: ActivatedRouteSnapshot): boolean { const user = this.getCurrentUser(); const authorizeFn = route.data?.['authorize']; return authorizeFn ? authorizeFn(user) : true; } // 根据路由路径匹配路由配置,判断权限 hasPermissionForPath(path: string): boolean { // 递归查找对应路径的路由配置(支持嵌套路由) const targetRoute = this.findRouteByPath(this.router.config, path); if (!targetRoute) return false; const user = this.getCurrentUser(); const authorizeFn = targetRoute.data?.['authorize']; return authorizeFn ? authorizeFn(user) : true; } private findRouteByPath(routes: Routes, path: string): ActivatedRouteSnapshot | null { for (const route of routes) { if (route.path === path) return route; if (route.children) { const found = this.findRouteByPath(route.children, path); if (found) return found; } } return null; } }
2. 在Dashboard组件中注入服务
在组件中引入PermissionService,供模板调用:
import { Component } from '@angular/core'; import { PermissionService } from './permission.service'; @Component({ selector: 'app-dashboard', templateUrl: './dashboard.component.html' }) export class DashboardComponent { constructor(public permissionService: PermissionService) {} }
3. 模板中用*ngIf控制链接显示
修改导航模板,通过权限判断决定是否显示链接:
<ul class="nav flex-column w-100 px-3"> <li class="nav-item" *ngIf="permissionService.hasPermissionForPath('admin-only')"> <a class="nav-link" routerLink="/admin-only">Admin Only</a> </li> <li class="nav-item" *ngIf="permissionService.hasPermissionForPath('admin-or-teacher')"> <a class="nav-link" routerLink="/admin-or-teacher">Admin Or Teacher</a> </li> </ul>
可选:批量渲染导航项(更易维护)
如果导航项较多,建议从路由配置中批量获取并渲染,避免重复写判断:
// Dashboard组件中新增代码 import { Router, Routes } from '@angular/router'; export class DashboardComponent { navRoutes: Routes = []; constructor(public permissionService: PermissionService, private router: Router) { // 获取DefaultLayout下的子路由,排除dashboard自身 const layoutRoute = this.router.config.find(route => route.path === ''); if (layoutRoute?.children) { this.navRoutes = layoutRoute.children.filter(route => route.path !== 'dashboard'); } } }
模板改成循环渲染:
<ul class="nav flex-column w-100 px-3"> <li class="nav-item" *ngFor="let route of navRoutes" *ngIf="permissionService.hasPermission(route)"> <a class="nav-link" [routerLink]="['/' + route.path]"> {{ route.path.replace('-', ' ') | titlecase }} </a> </li> </ul>
内容的提问来源于stack exchange,提问作者Shamseer K
相关产品推荐
相关产品推荐

