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

Angular点击事件异常:传入对象数组时需双击触发

问题分析与解决方案

问题症状

当向mdj-select-list组件传入对象类型数组时,需要双击.option元素才能触发selectOption()函数;但传入字符串类型数组时,单次点击即可正常触发。

根本原因

这个问题的核心在于Angular *ngFor的默认跟踪机制:

  • 对于字符串这类值类型,Angular会直接对比值是否相等,只要内容不变,不会重新渲染列表项。
  • 对于对象类型,Angular默认对比的是对象引用。如果父组件每次传递options时都是新建的数组(比如通过map、扩展运算符等方式生成新数组),即使数组内对象的内容没变,Angular也会判定为列表项需要重新渲染——第一次点击时,目标元素刚好被销毁并重建,导致点击事件丢失,第二次点击的是新渲染完成的元素,事件才能正常触发。

解决方案

给*ngFor添加trackBy函数,让Angular根据对象的唯一标识(比如value字段)来跟踪列表项,避免不必要的重渲染。

1. 修改组件类代码

在SelectListComponent中添加trackByOption函数:

import {
  Component,
  ElementRef,
  HostListener,
  Input,
  Output,
  ViewChild,
} from '@angular/core';

@Component({
  selector: 'mdj-select-list',
  templateUrl: './select-list.component.html',
  styleUrls: ['./select-list.component.scss'],
})
export class SelectListComponent {
  @Input()
  options: { label: string, value: string }[] = [];

  selectedOption: string;

  selectOption() {
    console.log('click');
  }

  // 添加trackBy函数,根据value字段跟踪选项
  trackByOption(index: number, option: { label: string, value: string }): string {
    return option.value;
  }
}

2. 修改模板代码

在*ngFor指令中绑定trackBy:

<div class="options-wrapper">
  <div *ngFor="let option of options; trackBy: trackByOption" class="option" (click)="selectOption()">
    {{ option.label }}
  </div>
</div>

额外优化

另外,建议在selectOption中传入当前选中的选项,这样能获取到点击的具体数据:

<div *ngFor="let option of options; trackBy: trackByOption" class="option" (click)="selectOption(option)">
  {{ option.label }}
</div>
selectOption(option: { label: string, value: string }) {
  this.selectedOption = option.value;
  console.log('选中选项:', option);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 08:36:11