输入模糊时隐藏弹出窗口,除非单击弹出窗口

Jul*_*tte 4 javascript events focus blur angular

我有以下用例:

有一个input,应该旁边时,它具有焦点的输入来显示弹出。因此,当input具有焦点时,用户可以输入input或使用弹出窗口来选择某些内容。

用户完成后,他可以通过单击其他位置或按 Tab 键并聚焦下一个元素来取消对元素的聚焦。但是,如果他单击弹出窗口内的按钮,弹出窗口应保持打开状态,输入应保持聚焦,以便用户可以继续键入。

我遇到的问题是,(click)在弹出窗口中处理输入之前,角度处理(模糊)。这意味着当用户在弹出窗口中点击时,输入失去焦点,它被隐藏,然后用户的点击将不再被处理。

我为这个问题制作了一个stackblitz-demo

这是源代码:

应用程序组件.html

<h1>Hello</h1>
<p>
    Type 'one', 'two' or 'three' to change number or select a number
    from popup.
    <br>
    <input type="checkbox" [(ngModel)]="hideHelperOnBlur" /> Hide
    helper on blur (if this is set, then the buttons in the popup don't work
    but if this is not set, the popup doesn't close if the input looses
    focus -> how can I get both? The buttons to work but the popup still
    closing on blur?)
</p>
    Your number: {{selectedNumber}}
<p>
Change number:
<input [ngModel]="formattedNumber" (ngModelChange)="newNumberTyped($event)" (focus)="helperVisible = true"
    (blur)="processBlur()" #mainInput />

<div *ngIf="helperVisible">
    <button *ngFor="let number of numbers" (click)="selectNumber(number.raw)">{{number.formatted}} </button>
</div>
Run Code Online (Sandbox Code Playgroud)

app.component.ts

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

@Component({
    selector: 'my-app',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    name = 'Angular';
    formattedNumber: string = 'three';
    selectedNumber: number = 3;
    helperVisible: boolean = false;
    numbers: any[] = [
        { raw: 1, formatted: 'one' },
        { raw: 2, formatted: 'two' },
        { raw: 3, formatted: 'three' }
    ];
    @ViewChild('mainInput', { static: false })
    mainInput: ElementRef;
    hideHelperOnBlur: boolean;

    newNumberTyped(newFormattedNumber: string) {
        this.numbers.forEach((number) => {
            if (newFormattedNumber == number.formatted) {
                this.formattedNumber = newFormattedNumber;
                this.selectedNumber = number.raw;
            }
        });
    }

    selectNumber(newRawNumber: number) {
        this.numbers.forEach((number) => {
            if (newRawNumber == number.raw) {
                this.formattedNumber = number.formatted;
                this.selectedNumber = newRawNumber;
            }
        });
        this.mainInput.nativeElement.focus();
    }

    processBlur() {
        if (this.hideHelperOnBlur) {
            this.helperVisible = false;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我期望以下行为:

  • 当输入获得焦点时,弹出窗口可见
  • 当用户点击页面上任何不是弹出窗口或输入的外部时,弹出窗口关闭
  • 当用户在输入焦点时按下选项卡,输入失去焦点并关闭弹出窗口
  • 当用户单击弹出窗口中的按钮时,该号码被选中

我似乎只能让第二个和第三个或第四个标准起作用(请参阅演示中的复选框)。

我已经尝试过的:

  • 将@HostListener 与 focusin、focusout 或 focus 或 (blur)="someFunction(event) 一起使用来找出哪个元素具有新焦点,以检查该元素是否在弹出窗口或输入中 -> 这似乎不起作用,因为在 focusout-event 时,尚不清楚谁获得了新的焦点
  • 使用超时,以便 Angular 在超时结束时已经完成对点击事件的处理 -> 这似乎有效,但使用超时是一个非常笨重的解决方案,可能很容易中断

有没有人有办法解决吗?

nas*_*h11 10

这更像是一个 Javascript 的东西。该blur事件发生之前click的事件。该click事件仅在释放鼠标按钮后发生。

您可以充分利用mousedown此处的活动。该mousedown事件发生之前blur的事件。只需调用preventDefaultmousedown的酥料饼按钮,以防止input失去焦点。在您这也将解决这一问题input闪烁,当您单击按钮酥料饼的,所以你可以摆脱this.mainInput.nativeElement.focus();你的selectNumber功能。

<button *ngFor="let number of numbers" (mousedown)="$event.preventDefault()" (click)="selectNumber(number.raw)">{{number.formatted}}</button>
Run Code Online (Sandbox Code Playgroud)

这是StackBlitz上的一个工作示例。

  • 很好的解决方案!谢谢@nash11 (2认同)
  • 我认为找到这个答案的最大困难是弄清楚如何表达查询来找到问题...... (2认同)