Angular 2指令阻止按钮点击事件失效问题求助
解决Angular指令中异步权限校验无法阻止点击事件的问题
我看了你的代码,核心问题出在权限校验是异步操作,但你在onClick里同步判断checkAuth()的返回值,这时候hasClaim还没被异步的subscribe赋值,导致逻辑完全出错——不管用户有没有权限,checkAuth()都会先返回初始的false,执行事件阻止操作,但等subscribe完成后hasClaim才会被正确赋值,可这时候已经晚了。
下面是修正后的完整代码,我会逐步解释关键改动:
1. 重构权限校验方法为异步返回Observable
把checkAuth()改成返回Observable<boolean>,利用RxJS操作符处理异步逻辑,同时避免内存泄漏:
import { take, map } from 'rxjs/operators'; @Directive({ selector: "[checkAuthOnClick]" }) export class CheckAuthorizationOnClickDirective { @Input() allowedClaim: any; @Output() stop: EventEmitter<Event> = new EventEmitter; constructor( private elementRef: ElementRef, private store: Store<fromRoot.State> ) {} @HostListener('click', ['$event']) async onClick(event: Event) { // 等待权限校验结果 const hasClaim = await this.checkAuth().toPromise(); if (!hasClaim) { // 无权限时彻底阻止事件 event.stopPropagation(); event.preventDefault(); event.stopImmediatePropagation(); (event as any).cancelBubble = true; // 兼容旧浏览器 this.stop.emit(event); } // 有权限时,事件会正常执行后续的(click)绑定逻辑 } private checkAuth(): Observable<boolean> { return this.store.select(fromRoot.currentUser).pipe( take(1), // 只取一次当前用户数据,避免内存泄漏 map(user => { if (!user || !this.allowedClaim) { return false; } let hasClaim = false; let description: string | undefined; if (Array.isArray(this.allowedClaim)) { // 用some替代循环,更简洁 hasClaim = this.allowedClaim.some(claim => user.hasClaim(claim)); description = this.allowedClaim[0]?.Description; } else { hasClaim = user.hasClaim(this.allowedClaim); description = this.allowedClaim?.Description; } if (!hasClaim) { const message = description ? `${description} yetkiniz yoktur.` : "Bu işlem için yetkiniz yoktur."; this.store.dispatch(new ui.ToastMessagePushAction({ severity: 'warning', summary: message, detail: '' })); } return hasClaim; }) ); } }
2. 关键改动说明
- 异步等待校验结果:把
onClick改成async方法,用await等待checkAuth()的结果,确保权限判断是在拿到用户数据之后才执行。 - RxJS操作符优化:用
take(1)获取当前用户的最新值后立即取消订阅,避免内存泄漏;用map操作符同步处理权限判断逻辑,替代原来的subscribe回调。 - 简化循环逻辑:用
Array.some()替代手动循环判断权限,代码更简洁易读。 - 移除冗余代码:删除了多余的
this.element = element.nativeElement,直接使用elementRef.nativeElement即可(当前代码里暂未用到它)。
3. 额外注意事项
- 确保你的Angular版本支持
async/await(Angular 5+都支持),如果版本较低,可以用subscribe替代await toPromise():@HostListener('click', ['$event']) onClick(event: Event) { this.checkAuth().subscribe(hasClaim => { if (!hasClaim) { // 阻止事件逻辑 event.stopPropagation(); event.preventDefault(); event.stopImmediatePropagation(); (event as any).cancelBubble = true; this.stop.emit(event); } }); } - 如果你发现PrimeNG按钮的点击事件还是无法阻止,可以尝试在无权限时直接禁用按钮(适合提前知道权限的场景):
// 在checkAuth的map逻辑中添加 if (!hasClaim) { // ...提示逻辑 this.elementRef.nativeElement.disabled = true; } else { this.elementRef.nativeElement.disabled = false; }
内容的提问来源于stack exchange,提问作者ebruszl
相关产品推荐
相关产品推荐

