You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 15+中mat-selection-list事件触发后代码阻塞至失焦问题

Angular 15+ mat-selection-list 焦点状态下代码阻塞问题

问题场景

在Angular 15+项目中使用mat-selection-list实现单选列表,初始加载时子组件能正常接收输入值,但切换列表项时,ngModelChange事件触发正常,但代码卡在实例化IdNotify的位置,直到点击列表外失焦后才继续执行,子组件才收到更新。绑定click事件也无法解决该问题。

相关代码

模板代码(mat-selection-list)

<mat-selection-list #contactsList [(ngModel)]="selectedAssociation" (ngModelChange)="onAssociateSelectionChanged($event)" [multiple]=false hideSingleSelectionIndicator=true>
  <mat-list-option *ngFor="let contact of model_list?.list; index as i; first as isFirst" color="primary" [value]="contact" [selected]="isFirst" >
    <mat-icon matListItemIcon class="mat-list-item-icon">{{contactClassIcons[contact.contact_types_id!]}}</mat-icon>
    <div matListItemTitle class="profile-line-primary">
      {{contact.contact_typeclass_title}}
    </div>
    <div matListItemLine class="profile-line-secondary">
      {{contact.contact_info}}
    </div>
  </mat-list-option>
</mat-selection-list>

父组件TS代码

idNotify: IdNotify;
onAssociateSelectionChanged(selectedAssociationList:ProfileContact[] | ProfileAcademy[]){
  console.log('SelectedContact:',selectedAssociationList)
  let selectedAssociationModel : ProfileContact | ProfileAcademy = (selectedAssociationList.length == 0 && this.model_list!.list.length >0)? this.model_list?.list[0] : selectedAssociationList[0];
  this.idNotify = // 准备向下游传递数据
    new IdNotify()  // <----**代码卡在此处**
  console.log('sending downstream ', selectedAssociationModel)
}

子组件模板引用

<profile-contact-edit [idNotify]="idNotify"></profile-contact-edit>

子组件TS代码(setter接收输入)

@Input() set idNotify(id: IdNotify) {
  console.log(`id   ${JSON.stringify(id)}  `) 
}

解决方案

1. 利用NgZone强制触发同步执行

Angular在组件焦点状态下可能延迟变更检测,通过NgZone的run方法可强制代码同步执行,确保数据及时更新:

import { NgZone } from '@angular/core';

// 构造函数注入NgZone
constructor(private ngZone: NgZone) {}

onAssociateSelectionChanged(selectedAssociationList:ProfileContact[] | ProfileAcademy[]){
  console.log('SelectedContact:',selectedAssociationList)
  let selectedAssociationModel : ProfileContact | ProfileAcademy = (selectedAssociationList.length == 0 && this.model_list!.list.length >0)? this.model_list?.list[0] : selectedAssociationList[0];
  
  this.ngZone.run(() => {
    // 补充传入selectedAssociationModel的必要数据到IdNotify
    this.idNotify = new IdNotify(selectedAssociationModel.id); 
    console.log('sending downstream ', selectedAssociationModel)
  });
}

2. 手动触发变更检测

若NgZone方法无效,可注入ChangeDetectorRef手动标记并触发变更检测:

import { ChangeDetectorRef } from '@angular/core';

// 构造函数注入ChangeDetectorRef
constructor(private cdr: ChangeDetectorRef) {}

onAssociateSelectionChanged(selectedAssociationList:ProfileContact[] | ProfileAcademy[]){
  console.log('SelectedContact:',selectedAssociationList)
  let selectedAssociationModel : ProfileContact | ProfileAcademy = (selectedAssociationList.length == 0 && this.model_list!.list.length >0)? this.model_list?.list[0] : selectedAssociationList[0];
  
  this.idNotify = new IdNotify(selectedAssociationModel.id); 
  console.log('sending downstream ', selectedAssociationModel);
  
  // 手动触发变更检测
  this.cdr.markForCheck();
  // 或使用detectChanges()立即执行检测
  // this.cdr.detectChanges();
}

3. 排查IdNotify构造逻辑

检查IdNotify的构造函数是否存在同步耗时操作或隐性阻塞逻辑,如果有,将其改为异步处理避免主线程阻塞:

// 父组件中
async onAssociateSelectionChanged(selectedAssociationList:ProfileContact[] | ProfileAcademy[]){
  console.log('SelectedContact:',selectedAssociationList)
  let selectedAssociationModel : ProfileContact | ProfileAcademy = (selectedAssociationList.length == 0 && this.model_list!.list.length >0)? this.model_list?.list[0] : selectedAssociationList[0];
  
  this.idNotify = await this.createIdNotify(selectedAssociationModel);
  console.log('sending downstream ', selectedAssociationModel);
  this.cdr.detectChanges();
}

private async createIdNotify(model: ProfileContact | ProfileAcademy): Promise<IdNotify> {
  const notify = new IdNotify();
  // 替换为实际异步初始化逻辑
  // notify.data = await this.someService.fetchExtraData(model.id);
  return notify;
}

说明

问题根源大概率是Angular在组件焦点状态下延迟处理变更检测队列,或IdNotify实例化过程中存在隐性阻塞。通过上述方法可确保数据更新及时同步到子组件,无需等待列表失焦。

内容的提问来源于stack exchange,提问作者Timy Shark

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 09:15:35