角度 7 |主机侦听器模糊条件停止所有其他事件回调



我有一个要求,我们希望用户解决输入字段错误,在此之前,不允许用户在屏幕上执行任何其他操作。

同样,我已经在输入字段上实现了 HostListener,并且在 onBlur 上,如果有验证方案失败,我将焦点设置回输入字段。

而且,我正在执行 e.preventDefault(( 和 e.stopPropagtion(( 来停止要在页面上执行的所有其他事件回调(因为在设置focus后,blur将是第一个要执行的事件(。

但不知何故,在任何外部事件上,blur确实被执行,但它并不限制要执行的其他事件。这些也在执行,没有它们我就无法实现所需的功能。

import { Directive, HostListener, Input } from '@angular/core';
@Directive({
selector: '[appNumberFormat]'
})
export class NumberFormatDirective {
constructor() { }
@HostListener('blur', ['$event']) blur(evt) {
evt.preventDefault();
console.log('field focus...');
evt.target.focus();
return false;
// if (evt.target.value.trim() === '') {
//     this.formControl.control.setValue(this.defaultValue);
// }
}
}

我在stackBlitz中复制了相同的场景。请看一看。

https://stackblitz.com/edit/angular-54ermg

模糊不会阻止另一个事件,因为它是独立运行的。将指针事件设置为无将阻止单击。

onBlur(e) {
e.preventDefault();
e.stopPropagation();
document.body.style.pointerEvents = 'none';
console.log('field focus...');
setTimeout(() => {
e.target.focus();
}, 10);
setTimeout(() => {
document.body.style.pointerEvents = 'initial';
}, 300);
return;
}

您还可以在聚焦输入时添加叠加层,而不是使用pointer-events: none。在这两种情况下,您都需要处理标签印刷机。

为了防止在输入元素上添加选项卡+输入:

(keydown)="onKeyDown($event)" 

在组件 ts 中:

onKeyDown(event) {
if (event.code === 'Tab') {
event.preventDefault();
event.stopPropagation();
}
}

您可以做的一种方法是使用此解决方案禁用页面上的所有事件(并为不允许回车键的按键进行自定义(。

停止所有事件的传播

disableAllUserEvents = () => {
const events = ["click", "contextmenu", "dblclick", "mousedown", "mouseenter", "mouseleave", "mousemove",
"mouseover", "mouseout", "mouseup", "blur", "change", "focus", "focusin",
"focusout", "input", "invalid", "reset", "search", "select", "submit", "drag", "dragend", "dragenter",
"dragleave", "dragover", "dragstart", "drop", "copy", "cut", "paste", "mousewheel", "wheel", "touchcancel",
"touchend", "touchmove", "touchstart"];
const handler = event => {
event.stopPropagation();
event.preventDefault();
return false;
};
for (let i = 0, l = events.length; i < l; i++) {
document.addEventListener(events[i], handler, true);
}
return () => {
for (let i = 0, l = events.length; i < l; i++) {
document.removeEventListener(events[i], handler, true);
}
};
};

并在一切正常时重新启用该事件。这有点蛮力,但它确实有效。

https://stackblitz.com/edit/angular-68vdrq

我认为这不是实现所需功能的理想方式。我认为当表单中出现错误时,其他按钮/锚链接应保持禁用状态。您可以将按钮和锚链接的禁用属性绑定到一个函数,该函数将在检查验证后返回 true/false。

尽管如此,浏览器还是按特定顺序执行事件,如果您需要停止点击事件进行,则应返回 false。我已经通过使用布尔变量实现了相同的方法,该变量将根据验证检查设置为 true/false,我在这里创建了您的代码分支 - https://stackblitz.com/edit/angular-uay8rm

preventOtherActions: boolean = true;
txtBoxValue: string = "";
submitForm($event) {
if(this.preventOtherActions) {
return false;
}
console.log('submitForm');
}
onBlur(e) {
console.log('field focus...');
setTimeout(() => {
e.target.focus();
}, 10);
this.preventOtherActions = this.txtBoxValue.length < 6;    
return;
}

您可以添加一个额外的 Input 属性来启用/禁用焦点功能。如果你有一个反应式表单,你可以把它挂接到表单的 VALID 状态。

export class NumberFormatDirective {
@Input() enableTargetFocus: boolean;
@HostListener('blur', ['$event']) blur(evt) {
if (this.enableTargetFocus === false) {
return;
}
...
}
}

.HTML:

<input type="text" appNumberFormat [enableTargetFocus]="form.invalid" />

解决此问题的一种方法是通过组件上的变量(指示表单是否有效(和阻止所有点击的简单 css 元素。

不过,你必须小心,并确保你专注于正确的元素,而且这不会永远持续下去,因为我不得不说,从用户体验的角度来看,这似乎相当烦人。

在您的 html 模板上:

<div *ngIf="formIsInvalid" class="click-blocker"></div>

在你的 css 上:

.click-blocker {
position: absolute;
background-color: rgba(1, 1, 1, 0.1); // adjust the opacity as you wish
bottom: 0;
left: 0;
right: 0;
top: 0;
height: 100vh;
width: 100vw;
z-index: 1;
}

我把它实现到你的堆栈闪电战中:https://stackblitz.com/edit/angular-za1lgx

我不太确定您要实现什么,但一个技巧可能是根据您在 onBlur(( 中调用的不同情况限制您的 focus(( 执行,因为自从您绑定事件以来,每次请求模糊时都会调用您。

为了防止执行,您可以仅在需要时触发它,但这并不理想:假设当您的e.targete.relatedTarget不是您想要的或类似的东西时,或者当document.activeElement已经是输入时,您不需要重新关注它模糊(( 但再次......不理想

希望这有帮助!