Angular指令:如何在模板中直接将第一个指令的输出作为第二个指令的输入
实现指令间直接传值的两种简洁方案
你想要跳过组件中间变量,直接把dmKeyDownDetect的输出传给dmKeyDownReact,有两种实用的实现方式:
方案一:模板内通过Observable+async管道绑定
这种方式不需要大幅修改指令逻辑,只给dmKeyDownDetect加一个Observable属性,就能在模板里直接绑定:
第一步:修改dmKeyDownDetect指令
把原有的EventEmitter换成Subject,同时保留输出事件兼容原有逻辑:
import { Directive, Input, ElementRef, Output, EventEmitter } from '@angular/core'; import { fromEvent, Subject } from 'rxjs'; import { filter, map } from 'rxjs/operators'; @Directive({ selector: '[dmKeyDownDetect]' }) export class DmKeyDownDetectDirective { @Input() detect: string[] = []; // 新增:暴露一个Observable供模板绑定 keyDetected$ = new Subject<string>(); // 保留原有输出事件,不影响其他使用场景 @Output() exactKeyDownDetected = this.keyDetected$.asObservable(); constructor(private el: ElementRef) { fromEvent(el.nativeElement, 'keydown') .pipe( map((e: KeyboardEvent) => e.key), filter(key => this.detect.includes(key)) ) .subscribe(key => this.keyDetected$.next(key)); } }
第二步:模板里直接绑定
用模板引用变量拿到指令实例,通过async管道把Observable的值传给dmKeyDownReact:
<input #detectDir="dmKeyDownDetect" dmKeyDownDetect [detect]="['/']" [dmKeyDownReact]="detectDir.keyDetected$ | async" [action]="actionToDo" >
方案二:指令间直接依赖注入通信
如果想彻底去掉模板里的绑定逻辑,可以让dmKeyDownReact直接注入dmKeyDownDetect,订阅它的输出事件:
第一步:修改dmKeyDownReact指令
注入dmKeyDownDetect实例,直接订阅其输出:
import { Directive, Input, Optional } from '@angular/core'; import { DmKeyDownDetectDirective } from './dm-key-down-detect.directive'; @Directive({ selector: '[dmKeyDownReact]' }) export class DmKeyDownReactDirective { @Input() action: () => void; // 用@Optional避免指令单独使用时报错 constructor(@Optional() private detectDir: DmKeyDownDetectDirective) { if (this.detectDir) { this.detectDir.exactKeyDownDetected.subscribe(key => { // 这里可以根据key做不同处理,比如判断是'/'还是'Escape' this.action?.(); }); } } }
第二步:模板简化写法
现在只需要同时应用两个指令,不用任何中间绑定:
<input dmKeyDownDetect [detect]="['/']" dmKeyDownReact [action]="actionToDo" >
这两种方案都能实现你要的效果,不用在组件里定义额外变量。
内容的提问来源于stack exchange,提问作者Riccardo Fachin
相关产品推荐
相关产品推荐

