Angular 5:如何通过ElementRef获取列表项的属性值?
嘿,我来帮你搞定这个authorize指令!你的需求是让这个指令作用在导航栏的<ul>上,自动抓取每个子<li>里的[routerLink]值,以此来做权限校验,简化导航栏的HTML代码对吧?下面是一步步的实现方案:
1. 创建AuthorizeDirective指令
首先生成指令(或者手动创建),这个指令会自动收集所有子元素的路由链接,然后做权限判断:
import { Directive, ContentChildren, QueryList, AfterContentInit, ElementRef, Renderer2 } from '@angular/core'; import { RouterLink, RouterLinkWithHref } from '@angular/router'; // 假设你有一个权限服务,用来判断用户权限 import { AuthService } from './auth.service'; @Directive({ selector: '[authorize]' }) export class AuthorizeDirective implements AfterContentInit { // 获取所有带有RouterLink或RouterLinkWithHref的子元素 @ContentChildren(RouterLink, { descendants: true }) routerLinks!: QueryList<RouterLink>; @ContentChildren(RouterLinkWithHref, { descendants: true }) routerLinkWithHrefs!: QueryList<RouterLinkWithHref>; constructor( private el: ElementRef, private renderer: Renderer2, private authService: AuthService // 注入权限服务 ) { } ngAfterContentInit(): void { // 处理已有的路由链接 this.processLinks(); // 如果导航项是动态生成的,监听链接变化 this.routerLinks.changes.subscribe(() => this.processLinks()); this.routerLinkWithHrefs.changes.subscribe(() => this.processLinks()); } private processLinks(): void { // 合并两种类型的路由链接实例 const allLinks = [...this.routerLinks.toArray(), ...this.routerLinkWithHrefs.toArray()]; allLinks.forEach(link => { const routePath = link.routerLink; console.log('当前路由路径:', routePath); // 调用权限服务判断用户是否有权限访问 const hasAccess = this.authService.canAccessRoute(routePath); // 根据权限控制导航项显示/隐藏 const parentLi = link.elementRef.nativeElement.closest('li'); if (parentLi) { if (!hasAccess) { this.renderer.setStyle(parentLi, 'display', 'none'); // 或者直接移除元素:this.renderer.removeChild(this.el.nativeElement, parentLi); } else { this.renderer.removeStyle(parentLi, 'display'); } } }); } }
2. 编写配套的AuthService(示例)
为了让权限逻辑更清晰,建议把权限判断放到单独的服务里:
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class AuthService { // 假设当前用户的权限列表 private userPermissions = ['dashboard', 'profile']; canAccessRoute(routePath: any[]): boolean { // 提取路由的第一个路径段(比如['/dashboard']取'dashboard') const routeSegment = routePath[0].replace('/', ''); return this.userPermissions.includes(routeSegment); } }
3. 在模块中声明指令
记得把指令添加到你的模块(比如AppModule)的declarations数组里:
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { RouterModule } from '@angular/router'; import { AuthorizeDirective } from './authorize.directive'; import { AppComponent } from './app.component'; // 导入你的组件 import { DashboardComponent } from './dashboard/dashboard.component'; import { ProfileComponent } from './profile/profile.component'; import { AdminComponent } from './admin/admin.component'; @NgModule({ declarations: [ AppComponent, AuthorizeDirective, DashboardComponent, ProfileComponent, AdminComponent ], imports: [ BrowserModule, RouterModule.forRoot([ { path: 'dashboard', component: DashboardComponent }, { path: 'profile', component: ProfileComponent }, { path: 'admin', component: AdminComponent }, { path: '', redirectTo: '/dashboard', pathMatch: 'full' } ]) ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
4. 在导航栏中使用指令
就像你原来的代码那样,直接给<ul>加上authorize属性即可:
<ul class="nav navbar-nav" authorize> <li [routerLinkActive]="['active']"> <a [routerLink]="['/dashboard']">仪表盘</a> </li> <li [routerLinkActive]="['active']"> <a [routerLink]="['/profile']">个人资料</a> </li> <li [routerLinkActive]="['active']"> <a [routerLink]="['/admin']">管理员后台</a> </li> </ul>
几个关键注意点
- 用
@ContentChildren而非直接操作DOM:这样能正确获取Angular绑定的routerLink值,而不是去解析原生HTML属性,更符合Angular的最佳实践。 - 支持动态导航项:通过监听
QueryList的changes事件,即使导航项是用*ngFor动态生成的,也能正确处理权限。 - 权限逻辑解耦:把权限判断放到
AuthService里,便于后续修改和测试,也能在其他组件/指令中复用。 - 优雅操作DOM:用
Renderer2来修改元素样式或移除元素,避免直接操作原生DOM,适配SSR等场景。
内容的提问来源于stack exchange,提问作者Michael Wolf Hoffman
相关产品推荐
相关产品推荐

