Angular中点击事件需二次触发的问题排查
问题原因与修复方案
核心问题
点击建议项时,输入框的blur事件会先于click事件触发,导致priceFocused被设为false,建议框通过*ngIf被销毁,此时click事件因元素已不存在无法执行。第一次点击实际只是触发了输入框失焦、隐藏建议框,第二次点击时输入框重新获焦显示建议框,才能触发点击逻辑。
修复方案一:监听全局点击事件(推荐)
通过监听document点击,判断点击区域是否为输入框或建议框,避免误触发隐藏逻辑。
修改后的HTML代码
<div class="input-field width-100"> <label>Price</label> <input autocomplete="off" type="number" class="w-100" value="0.00" name="price" (focus)="showPriceSuggestions()" [(ngModel)]="currentInventory.price" (ngModelChange)="onFieldChange()"> <!-- 添加模板引用变量 #priceSuggestions --> <div #priceSuggestions class="suggestions suggestions-wider" *ngIf="priceFocused"> <ul> <ng-container *ngIf="currentInventory.card.tcgplayer.prices != null"> <ng-container *ngFor="let price of formatPriceData()"> <li class="card-choice" *ngIf="price != null" (click)="selectPrice(price[1])"> <div class="row"> <div class="col-8"> {{price[0]}} </div> <div class="col-4"> ${{price[1]}} </div> </div> </li> </ng-container> </ng-container> </ul> </div> </div>
修改后的TS代码
import { Component, ElementRef, Renderer2, ViewChild } from '@angular/core'; // 替换为你的组件类名 export class InventoryComponent { public priceFocused: boolean = false; @ViewChild('priceSuggestions') priceSuggestions!: ElementRef; private clickListener?: () => void; constructor(private el: ElementRef, private renderer: Renderer2) {} showPriceSuggestions() { this.priceFocused = true; // 仅在显示建议框时监听全局点击 if (!this.clickListener) { this.clickListener = this.renderer.listen('document', 'click', (event) => { this.handleOutsideClick(event); }); } } selectPrice(price: number) { this.currentInventory.price = price; this.priceFocused = false; // 移除全局监听 this.cleanupClickListener(); } private handleOutsideClick(event: MouseEvent) { const inputElement = this.el.nativeElement.querySelector('input[name="price"]'); const suggestionsEl = this.priceSuggestions?.nativeElement; // 点击区域不是输入框也不是建议框时,隐藏建议 if (!inputElement.contains(event.target) && (!suggestionsEl || !suggestionsEl.contains(event.target))) { this.priceFocused = false; this.cleanupClickListener(); } } private cleanupClickListener() { if (this.clickListener) { this.clickListener(); this.clickListener = undefined; } } // 移除原有的priceFieldBlur方法 }
修复方案二:利用mousedown事件顺序
mousedown事件触发时机早于blur,因此可以用mousedown替代click处理选择逻辑,避免元素被提前销毁。
修改后的HTML代码(仅修改li部分)
<li class="card-choice" *ngIf="price != null" (mousedown)="selectPrice(price[1])"> <div class="row"> <div class="col-8"> {{price[0]}} </div> <div class="col-4"> ${{price[1]}} </div> </div> </li>
修改后的TS代码
public priceFocused: boolean = false; showPriceSuggestions() { this.priceFocused = true; } selectPrice(price: number) { this.currentInventory.price = price; this.priceFocused = false; } priceFieldBlur() { this.priceFocused = false; }
内容的提问来源于stack exchange,提问作者andresmonc
相关产品推荐
相关产品推荐

