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

为何Angular中用函数返回数组时*ngFor会导致输入框失焦?

问题原因分析

这个问题的核心在于Angular的变更检测机制以及*ngFor的默认追踪逻辑:

  1. 函数返回新数组引用:每次Angular触发变更检测(比如输入框获焦、按键事件后),都会执行模板中的testValues()函数。该函数每次调用都会返回一个全新的数组对象([{a:0}, {a:1}]是每次调用时重新创建的新引用)。
  2. *ngFor的默认追踪规则:*ngFor默认通过对象引用判断列表项是否变化。当数组引用改变时,Angular会认为所有列表项都是新元素,于是销毁原有的DOM节点(包括输入框)并重新创建。这就导致输入框刚获焦就被重建,自然无法正常输入。

而直接在模板中写字面量数组[{a:0}, {a:1}]时,这个数组的引用在组件生命周期内是固定不变的,*ngFor不会触发DOM重建,输入框就能正常工作。


解决方案

方案1:将数组存储为组件属性

把数组提前初始化到组件的属性中,避免在模板中调用函数生成新数组:

组件代码修改:

export class AppComponent {
  // 提前初始化数组,保持引用稳定
  testValues = [{ a: 0 }, { a: 1 }];

  testFocus($event: FocusEvent) {
    console.log('focus ', $event);
  }
}

模板修改:

<div *ngFor="let d of testValues">
  <input (focus)="testFocus($event)" type="text" />
</div>

方案2:使用trackBy自定义追踪逻辑

如果必须通过函数动态生成数组(比如数组内容依赖其他变量),可以通过trackBy告诉Angular如何识别唯一列表项,避免不必要的DOM重建:

组件代码添加trackBy函数:

export class AppComponent {
  testValues() {
    return [{ a: 0 }, { a: 1 }];
  }

  testFocus($event: FocusEvent) {
    console.log('focus ', $event);
  }

  // 自定义追踪函数,返回每个项的唯一标识
  trackByItemId(index: number, item: any): number {
    return item.a; // 用item的a属性作为唯一标识,也可以使用index
  }
}

模板修改:

<div *ngFor="let d of testValues(); trackBy: trackByItemId">
  <input (focus)="testFocus($event)" type="text" />
</div>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 04:35:28