如何为mat-select创建自定义指令监听change事件并解决事件捕获失败问题
问题原因
- Angular Material 的
mat-select是封装后的自定义组件,不会触发原生DOM的change事件,而是对外抛出自定义的selectionChange事件,因此你通过@HostListener('change')监听原生事件的方式无法捕获到mat-select的值变更。 - 另外
mat-select对应的DOM元素不是原生输入框,直接取elementRef.nativeElement.value也无法拿到正确的选中值。
解决方案
修改自定义指令,兼容原生输入框和mat-select两种场景,通过可选注入MatSelect实例的方式监听对应事件:
import { Directive, HostListener, Input, Optional, OnInit, OnDestroy, ElementRef } from '@angular/core'; import { MatSelect } from '@angular/material/select'; import { Subject, takeUntil } from 'rxjs'; // 保留你的原有其他导入 @Directive({ selector: '[appDeliveryAcross]' }) export class DeliveryAcrossDirective implements OnInit, OnDestroy { @Input('key') key: string = ''; @Input('component') component: string = ''; // 用于销毁订阅,避免内存泄漏 private destroy$ = new Subject<void>(); constructor( private store: Store, private elementRef: ElementRef<HTMLInputElement>, // 可选注入MatSelect,只有指令用在mat-select上时才会有实例 @Optional() private matSelect: MatSelect ) {} ngOnInit(): void { // 判断当前是否挂载在mat-select组件上 if (this.matSelect) { // 监听mat-select的selectionChange事件 this.matSelect.selectionChange .pipe(takeUntil(this.destroy$)) .subscribe(event => { this.store.dispatch<IAction<IAdjust>>({ type: RDX_DELIVERY_ACROSS_ADJUST, payload: { key: this.key, // 直接从事件中拿到选中值 value: event.value }, component: this.component }) }) } } // 原有逻辑保留,用于原生input的change事件监听 @HostListener('change') onChange() { // 仅当不是mat-select场景时走原有逻辑,避免重复触发 if (!this.matSelect) { this.store.dispatch<IAction<IAdjust>>({ type: RDX_DELIVERY_ACROSS_ADJUST, payload: { key: this.key, value: this.elementRef.nativeElement.value }, component: this.component }) } } ngOnDestroy(): void { this.destroy$.next(); this.destroy$.complete(); } }
修改后不需要改动你原有组件的模板代码,指令可以同时适配原生input和mat-select两种使用场景。
内容的提问来源于stack exchange,提问作者Noah Bergh
相关产品推荐
相关产品推荐

