Javascript 如何在不滚动的情况下显示html5验证消息?

Javascript 如何在不滚动的情况下显示html5验证消息?,javascript,jquery,html,validation,scroll,Javascript,Jquery,Html,Validation,Scroll,我试图定制HTML5验证的行为。当用户点击提交时,我希望无效字段滚动到页面中间。我的第一次尝试是这样做,但没有成功: $.each($("input, select"), function (index, input) { input.addEventListener("invalid", function () { this.scrollIntoView({ block: 'center',

我试图定制HTML5验证的行为。当用户点击提交时,我希望无效字段滚动到页面中间。我的第一次尝试是这样做,但没有成功:

    $.each($("input, select"), function (index, input) {
        input.addEventListener("invalid", function () {
            this.scrollIntoView({
                block: 'center',
                behavior: 'smooth'
            });
        });
    });

它不起作用,因为默认的滚动行为,即立即将无效字段滚动到页面顶部(即不平滑),会覆盖我试图在scrollIntoView(…)选项中指定的行为

于是我尝试了这个:

    $.each($("input, select"), function (index, input) {
        input.addEventListener("invalid", function (e) {
            e.preventDefault();
            this.scrollIntoView({
                block: 'center',
                behavior: 'smooth'
            });
        });
    });

添加preventDefault()允许发生我指定的滚动行为。但它也可以防止无效字段聚焦和验证消息出现

所以我的问题是:有没有一种方法可以让验证消息在不滚动的情况下弹出

大概是这样的:

    $.each($("input, select"), function (index, input) {
        input.addEventListener("invalid", function (e) {
            e.preventDefault();
            this.scrollIntoView({
                block: 'center',
                behavior: 'smooth'
            });
            this.focus();
            this.showValidationMessage();
        });
    });
我尝试过reportValidity(),但这会触发整个验证过程,这当然会破坏目的(即,它将调用默认滚动,从而覆盖我的自定义滚动)。我也尝试过checkValidity(),但这会导致“超过最大调用堆栈大小”,可能是因为它触发了“无效”事件,导致侦听器再次拾取该事件并无限期重复


任何帮助都将不胜感激。谢谢。

在Chrome上,调用
reportValidity()
时不会出现默认滚动。因此,问题只会出现在重复调用中,我们总是可以删除侦听器并重新绑定它:

function listener(e) {
   e.preventDefault();
   this.scrollIntoView({
      behavior: 'smooth',
      block: 'center'
   });
   this.focus();
   //removing the listener here
   $("#validateMe")[0].removeEventListener("invalid", listener);
   this.reportValidity();
   $("#validateMe")[0].addEventListener("invalid", listener);

}

$("#validateMe")[0].addEventListener("invalid", listener);
$("form").submit(function () {
   console.log("submitting");
});
这有点像黑客。。。但情况会变得更糟

这不会发生在FireFox或Edge上,所以我们需要一个不同的解决方案。。。老实说,我在网上什么地方都找不到。即使在HTML5的官方文档中,也没有单独调用信息泡沫的工作。然而,我确实尝试过超时,当事情发生得太快时,我总是求助于超时:

function listener(e) {
   e.preventDefault();
   this.scrollIntoView({
      behavior: 'smooth',
      block: 'center'
   });
   //removing the listener here
   $("#validateMe")[0].removeEventListener("invalid", listener);
   setTimeout(() => {
        this.focus();
        this.reportValidity();
        $("#validateMe")[0].addEventListener("invalid", listener);
   }, 500);
}

$("#validateMe")[0].addEventListener("invalid", listener);
$("form").submit(function () {
   console.log("submitting");
});
此解决方案适用于Chrome和Firefox。但不是边缘。它也只能根据滚动的速度和超时时间工作。因此,如果您将超时设置为较低的值,则错误消息会在浏览器滚动到您的输入之前提前弹出并冻结(除非您使用的是Chrome,这清楚地表明在这两种浏览器上实现的方式完全不同)


尽管这不是一个结论性的答案,但我认为你最好还是做一些手工的事情,而不是html5本身。这似乎并没有被认为是结束所有这些错误的错误反馈。使用插件、框架或尝试一些css魔术。

似乎没有任何方法可以仅阻止默认行为的滚动,而且实际上,即使有,UAs的不同行为也可能使这成为一个不合适的选项:当滚动无效元素时,Chrome会隐藏工具提示,因此不会显示它,Firefox使用此工具提示的固定位置,因此初始位置将关闭

因此,我能想到的唯一解决方案实际上是在平滑滚动完成后手动启动
reportValidity

不幸的是,当这种情况发生时,没有内置事件会触发,因此我们需要想出一个手工解决方案。
我们可以设置一个超时,但这是不可靠的:
执行此操作所需的时间没有标准,例如,该时间与所需的滚动量(即速度大于持续时间)相关,硬持续时间限制为3s(oO)

如果
reportValidity
的滚动在平滑的滚动完成之前发生,那么它将以
行为直接跳转:“最近的”
模式,破坏您的脚本:

const input=document.querySelector('input');
input.oninvalid=(evt)=>{
if(输入、强制、无效){
输入。_强制_无效=false;
返回;
}
evt.preventDefault();
input.scrollIntoView({
行为:“平滑”,
块:“中心”
} )
设置超时(()=>{
输入。_强制_无效=真;
input.reportValidity();
},200);//硬编码的值
};
p{
高度:1000vh;
宽度:5px;
背景:重复0 0/5px 10px
线性梯度(至底部,黑色50%,白色50%);
}

发送

发送
lol你把它砍到了核心。通过将方法setTimeout更改为
requestAnimationFrame
,并删除1000
requestAnimationFrame(()=>{this.focus();this.reportValidity();$(“#validateMe”)[0].addEventListener(“invalid”,listener);})
@joyBlanks设置超时不是因为我想等待一帧,而是因为他想让滚动动画平滑。这就是为什么setTimeout现在设置为500,因为我对它进行了微调以适应他的小提琴。虽然我会注意到RequestAnimationFrame-可能非常有用。当您在滚动完成后放入requestAnimation frame时,它将调用您的结果。比如说,感谢Artur完成了滚动,这就像一个符咒。我还发现,当滚动停止时,可以收听以下内容:谢谢Kaido。尽管我采用了阿图尔的解决方案,但你的方案看起来也同样有效。我会保存它,以备将来试用。@gibb65注意,尽管他们的超时解决方案远不可靠。至少在Chrome中,滚动时间不是由一个恒定的持续时间决定的,而是由一个速度决定的,也就是说,它与必须滚动的内容有关。硬编码超时可能会非常失败。