首页 >web前端 >js教程 >使用JavaScript即时表单验证

使用JavaScript即时表单验证

Christopher Nolan
Christopher Nolan原创
2025-02-16 10:40:10892浏览

实时表单验证:提升用户体验的微妙改进

Instant Form Validation Using JavaScript

核心要点:

  • JavaScript 可用于实现实时表单验证,此功能可为用户提供输入有效性的即时反馈,从而提升用户体验并维护数据完整性,确保仅提交有效数据。
  • HTML5 属性 patternrequired 可用于定义表单元素的有效输入范围。如果浏览器不支持这些属性,则其值可用作 JavaScript 兼容性填充程序的基础。
  • aria-invalid 属性可用于指示字段是否无效。此属性提供辅助功能信息,并可用作 CSS 钩子以直观地指示无效字段。
  • JavaScript 函数 instantValidation() 测试字段并执行实际验证,控制 aria-invalid 属性以指示字段的状态。此函数可以绑定到 onchange 事件以提供实时表单验证。

HTML5 引入了几个用于实现基于浏览器的表单验证的新属性。pattern 属性是一个正则表达式,用于定义文本区域元素和大多数输入类型的有效输入范围。required 属性指定字段是否必填。对于不支持这些属性的旧版浏览器,我们可以使用它们的值作为兼容性填充程序的基础。我们还可以使用它们来提供更有趣的增强功能——实时表单验证。

需要注意的是,不要过度使用验证,以免破坏正常的浏览行为并妨碍用户操作。例如,我见过一些表单,无法使用 Tab 键离开无效字段——JavaScript 被用来(更确切地说,是被滥用)强制焦点停留在字段内,直到其有效为止。这非常不利于用户体验,并且直接违反了辅助功能指南。

本文将介绍一种侵入性较小的实现方法。它甚至不是完整的客户端验证——它只是一种细微的用户体验增强,以可访问的方式实现,在我测试脚本时发现它几乎与 Firefox 当前原生实现的功能相同!

基本概念

在最新版本的 Firefox 中,如果必填字段为空或其值与模式不匹配,则该字段将显示红色边框,如下图所示:

Instant Form Validation Using JavaScript

当然,这不会立即发生。如果发生这种情况,则每个必填字段默认都会显示该边框。相反,只有在您与字段交互后才会显示这些边框,这基本上(虽然不完全)类似于 onchange 事件。

因此,我们将使用 onchange 作为触发事件。或者,我们可以使用 oninput 事件,该事件只要在字段中键入或粘贴任何值就会触发。但这真的太“即时”了,因为它很容易在快速连续键入时反复触发,从而产生闪烁效果,这会让一些用户感到厌烦或分心。而且,无论如何,oninput 不会从编程输入中触发,而 onchange 会触发,我们可能需要它来处理来自第三方插件的自动完成等操作。

定义HTML和CSS

让我们看一下我们的实现,从它所基于的 HTML 开始:

<code class="language-html"><form action="#" method="post">
  <fieldset>
    <legend><strong>Add your comment</strong></legend>

    <p>
      <label for="author">Name <abbr title="Required">*</abbr></label>
      <input aria-required="true" id="author" name="author" pattern="^([- \w\d\u00c0-\u024f]+)$" required="required" size="20" spellcheck="false" title="Your name (no special characters, diacritics are okay)" type="text" value="">
    </p>

    <p>
      <label for="email">Email <abbr title="Required">*</abbr></label>
      <input aria-required="true" id="email" name="email" pattern="^(([-\w\d]+)(\.[-\w\d]+)*@([-\w\d]+)(\.[-\w\d]+)*(\.([a-zA-Z]{2,5}|[\d]{1,3})){1,2})$" required="required" size="30" spellcheck="false" title="Your email address" type="email" value="">
    </p>

    <p>
      <label for="website">Website</label>
      <input id="website" name="website" pattern="^(http[s]?:\/\/)?([-\w\d]+)(\.[-\w\d]+)*(\.([a-zA-Z]{2,5}|[\d]{1,3})){1,2}(\/([-~%\.\(\)\w\d]*\/*)*(#[-\w\d]+)?)?$" size="30" spellcheck="false" title="Your website address" type="url" value="">
    </p>

    <p>
      <label for="text">Comment <abbr title="Required">*</abbr></label>
      <textarea aria-required="true" cols="40" id="text" name="text" required="required" rows="10" spellcheck="true" title="Your comment"></textarea>
    </p>

  </fieldset>
  <fieldset>
    <input name="preview" type="submit" value="Preview">
    <input name="save" type="submit" value="Submit Comment">
  </fieldset>
</form></code>

此示例是一个简单的评论表单,其中一些字段是必填的,一些字段经过验证,一些字段同时满足这两个条件。具有 required 属性的字段也具有 aria-required 属性,以便为不支持新输入类型的辅助技术提供后备语义。

ARIA 规范还定义了 aria-invalid 属性,我们将使用它来指示字段是否无效(HTML5 中没有等效属性)。aria-invalid 属性显然提供了辅助功能信息,但它也可以用作 CSS 钩子来应用红色边框:

<code class="language-css">input[aria-invalid="true"], textarea[aria-invalid="true"] {
  border: 1px solid #f00;
  box-shadow: 0 0 4px 0 #f00;
}</code>

我们可以只使用 box-shadow 而不用管边框,坦白说这样看起来会更好,但这样一来,在不支持 box-shadow 的浏览器(例如 IE8)中就没有指示了。

添加JavaScript

现在我们有了静态代码,我们可以添加脚本了。首先,我们需要一个基本的 addEvent() 函数:

<code class="language-javascript">function addEvent(node, type, callback) {
  if (node.addEventListener) {
    node.addEventListener(type, function(e) {
      callback(e, e.target);
    }, false);
  } else if (node.attachEvent) {
    node.attachEvent('on' + type, function(e) {
      callback(e, e.srcElement);
    });
  }
}</code>

接下来,我们需要一个函数来确定是否应该验证给定字段,该函数只需测试它既未禁用也未只读,并且它具有 patternrequired 属性:

<code class="language-javascript">function shouldBeValidated(field) {
  return (
    !(field.getAttribute("readonly") || field.readonly) &&
    !(field.getAttribute("disabled") || field.disabled) &&
    (field.getAttribute("pattern") || field.getAttribute("required"))
  );
}</code>

前两个条件可能看起来很冗长,但它们是必要的,因为元素的 disabledreadonly 属性不一定反映其属性状态。例如,在 Opera 中,具有硬编码属性 readonly="readonly" 的字段仍然会为其 readonly 属性返回 undefined(点属性只匹配通过脚本设置的状态)。

一旦我们获得了这些实用程序,我们就可以定义主验证函数,该函数测试字段,然后根据需要执行实际验证:

<code class="language-javascript">function instantValidation(field) {
  if (shouldBeValidated(field)) {
    var invalid =
      (field.getAttribute("required") && !field.value) ||
      (field.getAttribute("pattern") &&
        field.value &&
        !new RegExp(field.getAttribute("pattern")).test(field.value));
    if (!invalid && field.getAttribute("aria-invalid")) {
      field.removeAttribute("aria-invalid");
    } else if (invalid && !field.getAttribute("aria-invalid")) {
      field.setAttribute("aria-invalid", "true");
    }
  }
}</code>

因此,如果字段是必填的但没有值,或者它具有模式和值,但值与模式不匹配,则该字段无效。

由于模式已经定义了正则表达式的字符串形式,所以我们只需要将该字符串传递给 RegExp 构造函数,它就会创建一个我们可以针对该值进行测试的正则表达式对象。但是,我们必须预先测试该值以确保它不为空,这样正则表达式本身就不必考虑空字符串。

一旦我们确定了字段是否无效,我们就可以控制它的 aria-invalid 属性来指示该状态——将其添加到尚未具有该属性的无效字段中,或将其从具有该属性的有效字段中删除。很简单!最后,为了使这一切都能运行,我们需要将验证函数绑定到 onchange 事件。它应该像这样简单:

<code class="language-html"><form action="#" method="post">
  <fieldset>
    <legend><strong>Add your comment</strong></legend>

    <p>
      <label for="author">Name <abbr title="Required">*</abbr></label>
      <input aria-required="true" id="author" name="author" pattern="^([- \w\d\u00c0-\u024f]+)$" required="required" size="20" spellcheck="false" title="Your name (no special characters, diacritics are okay)" type="text" value="">
    </p>

    <p>
      <label for="email">Email <abbr title="Required">*</abbr></label>
      <input aria-required="true" id="email" name="email" pattern="^(([-\w\d]+)(\.[-\w\d]+)*@([-\w\d]+)(\.[-\w\d]+)*(\.([a-zA-Z]{2,5}|[\d]{1,3})){1,2})$" required="required" size="30" spellcheck="false" title="Your email address" type="email" value="">
    </p>

    <p>
      <label for="website">Website</label>
      <input id="website" name="website" pattern="^(http[s]?:\/\/)?([-\w\d]+)(\.[-\w\d]+)*(\.([a-zA-Z]{2,5}|[\d]{1,3})){1,2}(\/([-~%\.\(\)\w\d]*\/*)*(#[-\w\d]+)?)?$" size="30" spellcheck="false" title="Your website address" type="url" value="">
    </p>

    <p>
      <label for="text">Comment <abbr title="Required">*</abbr></label>
      <textarea aria-required="true" cols="40" id="text" name="text" required="required" rows="10" spellcheck="true" title="Your comment"></textarea>
    </p>

  </fieldset>
  <fieldset>
    <input name="preview" type="submit" value="Preview">
    <input name="save" type="submit" value="Submit Comment">
  </fieldset>
</form></code>

但是,为了使这能够工作,onchange 事件必须冒泡(使用通常称为事件委托的技术),但在 Internet Explorer 8 及更早版本中,onchange 事件不会冒泡。我们可以选择忽略这些浏览器,但我认为这将是一种遗憾,尤其是在问题如此容易解决的情况下。它只是意味着代码更复杂一些——我们必须获取输入和文本区域元素的集合,遍历它们并将 onchange 事件分别绑定到每个字段:

<code class="language-css">input[aria-invalid="true"], textarea[aria-invalid="true"] {
  border: 1px solid #f00;
  box-shadow: 0 0 4px 0 #f00;
}</code>

结论和展望

就是这样——一个简单且非侵入性的实时表单验证增强功能,提供可访问和直观的提示,以帮助用户完成表单。

这个脚本实现后,我们实际上只需要几步就能完成一个完整的兼容性填充程序。这样的脚本超出了本文的范围,但是如果您想进一步开发它,所有基本模块都在这里——测试是否应该验证字段,根据模式和/或 required 验证字段,以及绑定触发事件。

我必须承认,我不确定它是否真的值得!如果您已经有了此增强功能(在 IE7 及所有现代浏览器中都能工作),并且考虑到您别无选择,也必须实现服务器端验证,并且考虑到支持 patternrequired 的浏览器已经使用它们进行预提交验证——考虑到所有这些,真的还有必要添加另一个兼容性填充程序吗?

(此处可以添加关于实时验证的常见问题解答部分,内容与原文档中的FAQs部分相同)

以上是使用JavaScript即时表单验证的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn