当表单验证时,如何滚动到第一个错误而不是跳转?

64

我看到很多涉及此主题的问题,但我正在寻找简单明了的解决方案:

HTML表单,jQuery验证,需要多个字段。当提交表单时,验证会跳转到第一个错误并将其突出显示。为了提高可用性,我想滚动到第一个错误字段。但它仍然完全破坏验证或抛出scrollTo错误。

我需要使用标准验证插件(http://docs.jquery.com/Plugins/Validation),但任何滚动器都可以,尽管我一直在尝试使用scrollTo(http://flesler.blogspot.com/2007/10/jqueryscrollto.html)。

示例代码位于http://jsfiddle.net/DtgKQ/1/,感谢任何帮助。

9个回答

142

以下是您可以执行的操作:

  • 默认情况下,验证插件会将焦点放在第一个出错的元素上(如果有)。通过将选项focusInvalid设置为false来关闭它。

  • 当表单无效时,回调函数invalidHandler被执行。您可以通过第二个参数validator获得访问验证器对象及其errorList数组。然后,您可以相对于第一个出错的元素进行滚动动画。

以下是代码:

$("#commentForm").validate({
    focusInvalid: false,
    invalidHandler: function(form, validator) {

        if (!validator.numberOfInvalids())
            return;

        $('html, body').animate({
            scrollTop: $(validator.errorList[0].element).offset().top
        }, 2000);

    }
});

演示


7
搞定了: '$(validator.errorList[0].element).offset().top-20' 的意思是取得验证器中第一个错误元素相对于页面顶部的偏移量,再减去20像素。 - Heraldmonkey
7
太棒了!我还建议添加 $(validator.errorList[0].element).focus(); ,这样字段就会在验证后获得焦点。 - Dmitry Dzygin
2
最好在动画完成后,将其添加到匿名函数中,延迟2000毫秒执行。 - Mike Causer
1
如果无效元素已经可见,您也可以跳过向上滚动。在我看来,这样会更流畅。 - Mike Causer
4
如果元素在视口中,则跳过滚动。 @MikeCauser (https://dev59.com/6nVD5IYBdhLWcg3wAGeD#7557433) - James Harrington
显示剩余8条评论

13

我不喜欢所有的jQuery扩展,因此我有个解决方案:

if ($('#MYID').valid()) {
      //dosomething();
} else {
    $('html, body').animate({
         scrollTop: ($('.error').offset().top - 300)
    }, 2000);
}

$(...).valid不是一个函数(…) (jQuery版本2.2.1) - MilMike
2
@blackhatmario 这是jQuery Validation插件的一部分.valid() - mvanella

7
只需将以下代码添加到你的主题 JavaScript 文件中:
(function($) {
$(document).ready(function(){
    //bmo scroll to not valid
    $(".wpcf7").on('invalid.wpcf7',function(e){
        $('html, body').animate({
                scrollTop: $(".wpcf7-not-valid").first().offset().top-30
            }, 2000);
    });

});
})(jQuery);

5

针对使用HTML5验证和原生JavaScript的任何人:

这不是对于这个问题的直接回答,但由于在搜索这个问题时这是主要的帖子,我想我应该在这里发布我的解决方案,以供任何也在寻找答案的人使用!

我正在我的ReactJS项目中使用此方法,但它应该在几乎所有原生ES6 JavaScript设置中使用现代浏览器同样有效。

function scrollToInvalid(form) {
  const invalidInputs = Array.from(form.querySelectorAll(':invalid, .is-invalid [, .custom-invalid-selector]'));    // set up so you can use any custom invalid classes you're adding to your elements, as well
  invalidInputs.sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);                      // sort inputs by offset from top of viewport (handles issues with multi-column layouts, where the first element in the markup isn't necessarily the highest on the page)
  invalidInputs[0].scrollIntoView({ block: 'center', behavior: 'smooth' });                                         // scroll first (top) input into center of view, using smooth animation
}

function handleSubmit(e) {
  const form = e.currentTarget;

  if (form.checkValidity() === false ) {
    // form is invalid, don't submit
    e.preventDefault();
    e.stopPropagation();
    // scroll first invalid input into view
    scrollToInvalid(form);
  }
  else {
    // form is valid, handle submit...
  }
}
<form onSubmit="handleSubmit">
  ...
</form>


无法工作。如果表单无效,它将自动跳转到无效输入,因此handleSubmit永远不会被调用。 - darren z
无法工作。如果表单无效,它将自动跳转到无效输入,因此handleSubmit永远不会被调用。 - darren z
@darrenz 不确定浏览器实现是否有所改变,但是我已经在生产应用程序中使用这个完全相同的代码两年了,没有任何问题。请注意,这是针对原始JS和默认HTML5表单验证的答案 - 而不是jQuery验证。 - Fateh Khalsa

1

也许你可以检查哪个输入失败了,获取它的位置(顶部),并使用jQuery的scrollTop

$(window).scrollTop(errorPosition)

看起来获取每个错误字段并不容易(至少对我来说是这样)。

验证插件文档中搜索errorPlacement。有一个示例可以获取每个错误字段。


1

你可以尝试下面的代码,它使用纯JavaScript

setTimeout(function () {
            document
                .querySelector(".field-validation-error")
                .scrollIntoView({ behavior: "smooth", block: "center" });
        }, 0);

0
尝试这个:
$( "input[type=submit]" ).click(function() {
    event.preventDefault();
    event.stopPropagation();
    //  console.log("test")
    var errorElements = document.querySelectorAll(".input-validation-error");
  for (let index = 0; index < errorElements.length; index++) {
      const element = errorElements[index];
    //  console.log(element);
      $('html, body').animate({
        scrollTop: $(errorElements[0]).focus().offset().top - 25
      }, 1000);      
      return false;
  }
});

0
**Get the classname of input - get this div topoffset - move to this div**
beforeSubmit = function(){

setTimeout(scrollInput, 1000);
   
function scrollInput() {
   alert('hello');
    var list = document.getElementById("cpa-form").getElementsByClassName("has-error");
    if (list && list.length > 0) {
        var gimno = list[0].className;
        
        
        var classes = gimno.split(' ');
        
        var class2 = classes[1];
        
        console.log(class2);
        
        var topme = $('.'+ class2).offset().top;
        
        
        $('html, body').animate({scrollTop: '+='+topme+'px'}, 800);
        
    }
}

-1
  $("#create-form").validate({ // Set Focus on first invalid input
    focusInvalid: false,
    invalidHandler: function() {
      $(this).find(":input.error:first").focus();
      }
  });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接