表单验证失败后向下滚动到表单

Posted

技术标签:

【中文标题】表单验证失败后向下滚动到表单【英文标题】:Scroll down to form after form validation failure 【发布时间】:2020-08-27 17:09:14 【问题描述】:

我有一个 php 联系表单,提交时会验证字段,但此过程会重新加载页面并且表单不在页面顶部,所以我希望它自动滚动到表单所在的页面底部验证失败,因此用户可以看到错误。似乎 javascript 是执行此操作的唯一方法,因此我尝试将脚本与错误消息一起回显,但它不起作用。浏览器控制台中没有错误,只是不滚动。

在新页面加载后,我从查看源代码中获取已解析的 html,并将其放入 jsFiddle here。您可以看到它在小提琴中正确滚动,但实际站点没有。

编辑: 我还尝试将 jquery 库的加载添加到滚动脚本之前,即使我确认库首先加载,它仍然没有滚动。我很茫然。

这是一个sn-p的php:

<?php
// define variables and set to empty values
$nameErr = $fromErr = $phoneErr = $verif_boxErr = $recaptchaErr = "";
$name    = $from = $phone = $message = $verif_box = "";
$recaptcha = NULL;
$errors  = 0;

if ($_SERVER["REQUEST_METHOD"] == "POST")  //check if form has been submitted
    if (empty($_POST["name"])) 
        $nameErr = " * Name is missing";
        $errors  = 1;
        echo '<style type="text/css"> input#name border: 1px solid #F00; 
        box-shadow: 0px 0px 5pt .1pt #F00 inset;</style>
        <script type="text/javascript">
function scrollSmoothToBottom() 
$(scrollingElement).animate(scrollTop:document.body.scrollHeight,500)
scrollingElement=document.scrollingElement||document.body,
window.onload=scrollSmoothToBottom;</script>';
     else 
        $name = test_input($_POST["name"]);
        // check if name only contains letters and whitespace
        if (!preg_match("/^[a-zA-Z ]*$/", $name)) 
            $nameErr = "Only letters and white space allowed";
            $errors  = 1;
            echo '<style type="text/css"> input#name border: 1px solid #F00; box-shadow: 0px 0px 5pt .1pt #F00 inset;</style>';
        
    

if ($errors == 0)  // all fields successfullty validated. 
        $message = "Message: " . "\n" . $message;
        $message = "Name: " . $name . "\n\n" . $message;
        $message = "Email: " . $from . "\n" . $message;
        mail("website@avayoupaint.com", 'Contact Form: ' . $name, $message = "Sender IP Address: " . $_SERVER['REMOTE_ADDR'] . "\n\n" . $message, "From: website-html@avayoupaint.com");            
        setcookie('tntcon', '');    // delete the cookie so it cannot sent again by refreshing this page
        header('Location: success.php');    // redirect to success page
        exit();




?>
<html>
<head></head>
<body>
<article id="contactForm">                        
    <span class="error">* All fields are required</span>
    <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method="post" name="form1" id="form1">
    <span class="contactTitles">Name:</span>
    <input name="name" type="text" id="name" value="<?php echo $name;?>"/><span class="error"><?php echo $nameErr;?></span>
    </form> 
</article>
</body>
</html>

【问题讨论】:

我去了你的real site(来自你已删除问题的链接)。我将代码复制到一个空白文件中(而不是使用 JSFiddle,它有时会扭曲事物)。我将console.log(scrollingElement); 添加到scrollSmoothToBottom 函数中。它运行,但记录null,因此它没有找到该元素。这是因为脚本在呈现 HTML 文档之前加载和执行 - 窗口可能已加载,但文档未加载。因此它找不到要附加“动画”功能的主体元素。 两种可能的解决方案:1)将脚本移动到页面底部,就在关闭&lt;/body&gt;标记之前,所以它不会执行,直到所有的HTML都被加载(浏览器加载并执行每个标签在他们找到它的那一刻,他们不会等待所有内容加载)。 2) 将脚本包装在$(document).ready 块中(正如我在之前的聊天中所建议的那样),因此在所有 HTML 准备好之前它不会执行 - 因为那个“准备”事件直到那时才会触发。 无论哪种方式,您还应该 1) 确保脚本位于页面的 &lt;head&gt;&lt;body&gt; 标记内,否则从技术上讲它会使 HTML 文档无效。一些浏览器可能会容忍这种情况并运行脚本,但你不应该依赖它。 2) 确保只在页面中加载一次 jQuery——现在你在两个不同的地方加载了两次——这有时会导致奇怪的副作用和问题。 3) 使用更新版本的 jQuery。 1.x 分支只有在你必须支持像 IE8 这样的非常老的浏览器时才需要,但实际上应该没有人需要它了。 P.S.您在上述问题中发布的 90% 的代码与问题完全无关。不清楚为什么您会期望发送电子邮件的服务器端函数与与滚动相关的客户端 Javascript 问题有任何关系?然而,您没有包含任何实际指向问题的代码。您所包含的只是一个 JSFiddle 的链接,它 没有 重现该问题(可能是因为 JSFiddle 将您发布的所有代码包装在另一个文档对象中(必须如此,所以它可以将它放在那个小框架中) ,所以它找到了元素,并掩盖了问题。 幸运的是我可以查看已删除的问题并检索到真实站点的链接,否则我们仍然对实际问题没有真正的线索。 【参考方案1】:

获取scrollingElement 变量的脚本在页面加载时立即运行,在所有HTML 准备好并加载到页面之前。您需要等到所有内容都加载完毕,否则脚本将找不到document.body 对象来附加滚动动画。这尤其是一个问题,因为脚本位于 HTML 文档之前。浏览器收到脚本后会立即执行,不会等到整个文档加载完毕。

jQuery 提供了document.ready 事件处理程序让您将 Javascript 包装在其中,以便主脚本等待页面处于所有 HTML 已加载的状态(也有一个本地 JS 方式来做同样的事情事情,但由于您使用的是 jQuery,我们将这样做)。实际上,您当前的站点中已经有一个这样的示例,就在底部附近。

scrollingElement 在函数内部也更有意义——它作为一个全局对象并没有太大的意义,因为它只在那个函数中使用。

<script type="text/javascript">
  $(document).ready(function() 

  function scrollSmoothToBottom()  
    var scrollingElement = document.scrollingElement || document.body;
    $(scrollingElement).animate( scrollTop:document.body.scrollHeight , 500);
  
    scrollSmoothToBottom();
  );
</script>

请注意,此版本需要在此脚本块运行之前加载 jQuery。在页面的 &lt;head&gt; 部分中的某处输出脚本块是有意义的,就在加载 jQuery 的 &lt;script 块下方。

【讨论】:

我认为window.onLoad 意味着浏览器确实等待整个文档加载。如果我将脚本移动到 html 中失败,我会试试这个。 是的。它类似于 document.ready/DOMContentLoaded。因此,如果您愿意,您可以坚持使用 onload。但是,如果您仔细查看原始代码,您定义 scrollingElement 的位不是 onload 事件的一部分,该行在 onload 之前执行 - 当脚本块被执行时,它将立即运行初始化,因此当您在函数中使用它时,为什么 scrollingElement 的值为 null。代码中由 onload 触发的唯一一点是对函数的调用。 这不起作用。我得到与尝试时相同的“未捕获的 RefenceError:$ 未定义”。我实际上在第一次尝试时使用了$(document).ready,然后由于错误而切换到window.onLoad 你可以混合一下。你不需要 all 你的 PHP 在头脑中。你只需要这么多:&lt;?php if ($errors == 1) echo '&lt;script type="text/javascript"&gt; $(document).ready(function() function scrollSmoothToBottom() var scrollingElement = document.scrollingElement || document.body; $(scrollingElement).animate( scrollTop:document.body.scrollHeight , 500); scrollSmoothToBottom(); ); &lt;/script&gt;'; ?&gt;。它的其余部分可以留在原处,以便在生成头部时可以检查 $errors 变量。 但一般来说,您应该将处理业务逻辑、验证、与数据库通信等的 PHP 分离到脚本的顶部(和/或分离到完全独立的脚本文件中的单独的类和函数中) , 并且只在你的主脚本中获得included,因此它们可以单独维护和重复使用),但是如果你需要一些 PHP 来控制发送到浏览器的最终输出,那么包含它是可以接受的并且显然是合乎逻辑的在一般静态 HTML 中的适当位置。

以上是关于表单验证失败后向下滚动到表单的主要内容,如果未能解决你的问题,请参考以下文章

当 iframe 的表单验证失败时,让父页面滚动到顶部

vue element ui表单验证不通过,滚动到页面上第一个验证失败的输入框位置

验证失败后,servlet中止多部分表单数据提交

表单验证失败后如何渲染模板?

表单验证失败后表单上的单选按钮无法正确呈现 - 引导

vue+Element表单验证之滚动条定位到校验未通过的表单控件的位置