首页 文章

移动目标元素时,不会触发单击处理程序

提问于
浏览
4

考虑以下演示https://stackblitz.com/edit/angular-pur1dt

我有反应式表单控件,同步验证程序和错误消息显示在字段下面无效时 .

当控制失去焦点时,将触发验证 . 控件下方有一个带有点击处理程序的按钮 . 问题是,当我单击按钮时,控件失去焦点,验证发生,显示错误消息并向下移动按钮 . 据说这可以防止点击处理程序执行 . 任何建议为什么会发生这种情况以及如何解决问题?

我已经用评论更新了演示 . 注意:输入下方的仅按钮将重现该问题 . 第一次单击它后, Headers 不会更新 .

3 回答

  • 4

    该问题似乎与触发订单的DOM事件有关

    据MDN称:

    在单个元素上按下并释放指点设备按钮(通常是鼠标的主按钮)时,将触发click事件 .

    https://developer.mozilla.org/en-US/docs/Web/Events/click

    在给定的示例中,元素会在您输入的那一刻移动 - 因为验证会立即发生,显示错误并重新定位按钮 .

    因此鼠标 is down when 在按钮上方时,但当 its up 时 - 按钮被重新定位 . 所以 click wont be triggered on the button

    有几种方法可以解决这个问题:

    • on mousedown 延迟错误显示

    • 隐藏错误,直到 mousedownmouseup 都发生,如果 mousedown 发生在按钮上

    以下是 mousedown 事件处理的示例https://jsfiddle.net/gjbgqqpo/

    希望这可以帮助 :)

  • 0

    这个问题在GitHub的issue #7113中讨论过 . 这是因为在单击按钮有机会完成并触发 click 事件之前,当输入字段失去焦点时执行验证 .

    一种可能的解决方法是使用标志来隐藏消息,同时单击按钮,如this stackblitz所示 . 在下面的代码中,在 mousedown 事件上单击开始时设置 isClicking 标志,并在 click 事件完成时重置该标志 .

    <p #errorMsg [hidden]="(errorMsg.hidden && isClicking) || form.controls.name.valid || form.controls.name.untouched ">
        Invalid :)
    </p>
    <button (mousedown)="onMouseDown($event)" (click)="onClick2($event)">click NOT ok</button>
    
    export class AppComponent {
    
      isClicking = false;
      ...
    
      onMouseDown(event) {
        this.isClicking = true;
        setTimeout(() => {
          // The click action began but was not completed after two seconds
          this.isClicking = false;
        }, 2000);
      }
    
      onClick2(event) {
        console.log(event);
        this.name = "NOT";
        this.isClicking = false;
      }
    }
    

    您可以通过将 setTimeout 替换为在 mousedown 事件处理程序中捕获鼠标的过程来更改该解决方案,并在捕获丢失时重置 isClicking . 它将解释用户在未完成点击的情况下离开按钮的情况 .

  • 1

    好的,我想我会跟着 . 单击下方按钮时,您不希望进行验证 .

    触发验证的原因是因为表单输入上的 autofocus . Angular "By default, the value and validity of a control updates whenever the value changes." See FormControl . 该控件正在将 name.untouchedfalse 更改为 true .

    如果您向模板添加一些额外的调试绑定,您可以观察到这种情况 . 例如

    <hello name="{{ name }}"></hello>
    <form [formGroup]="form">
        <input formControlName="name" autofocus>
        <button (click)="onClick($event)">click OK</button>
    </form>
    <pre>{{form.controls.name.valid}}</pre>
    <pre>{{form.controls.name.untouched}}</pre>
    <p [hidden]="form.controls.name.valid || form.controls.name.untouched ">
        Invalid :)
    </p>
    <button (click)="onClick2($event)">click NOT ok</button>
    

    如果要在用户单击下方按钮时隐藏错误消息,则应在调用 onClick2() 时删除 autofocus 或重置表单的验证 . 或者,您只能在表单出错时显示错误消息 . Angular说 A control is untouched if the user has not yet triggered a blur event on it. 单击下方按钮会导致模糊事件 .

    为什么不在错误消息上更改模板绑定

    <p [hidden]="!form.controls.name.valid || form.controls.name.untouched">
        Invalid :)
    </p>
    

相关问题