核心要点:
pattern
和 required
可用于定义表单元素的有效输入范围。如果浏览器不支持这些属性,则其值可用作 JavaScript 兼容性填充程序的基础。aria-invalid
属性可用于指示字段是否无效。此属性提供辅助功能信息,并可用作 CSS 钩子以直观地指示无效字段。instantValidation()
测试字段并执行实际验证,控制 aria-invalid
属性以指示字段的状态。此函数可以绑定到 onchange
事件以提供实时表单验证。HTML5 引入了几个用于实现基于浏览器的表单验证的新属性。pattern
属性是一个正则表达式,用于定义文本区域元素和大多数输入类型的有效输入范围。required
属性指定字段是否必填。对于不支持这些属性的旧版浏览器,我们可以使用它们的值作为兼容性填充程序的基础。我们还可以使用它们来提供更有趣的增强功能——实时表单验证。
需要注意的是,不要过度使用验证,以免破坏正常的浏览行为并妨碍用户操作。例如,我见过一些表单,无法使用 Tab 键离开无效字段——JavaScript 被用来(更确切地说,是被滥用)强制焦点停留在字段内,直到其有效为止。这非常不利于用户体验,并且直接违反了辅助功能指南。
本文将介绍一种侵入性较小的实现方法。它甚至不是完整的客户端验证——它只是一种细微的用户体验增强,以可访问的方式实现,在我测试脚本时发现它几乎与 Firefox 当前原生实现的功能相同!
基本概念
在最新版本的 Firefox 中,如果必填字段为空或其值与模式不匹配,则该字段将显示红色边框,如下图所示:
当然,这不会立即发生。如果发生这种情况,则每个必填字段默认都会显示该边框。相反,只有在您与字段交互后才会显示这些边框,这基本上(虽然不完全)类似于 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>
接下来,我们需要一个函数来确定是否应该验证给定字段,该函数只需测试它既未禁用也未只读,并且它具有 pattern
或 required
属性:
<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>
前两个条件可能看起来很冗长,但它们是必要的,因为元素的 disabled
和 readonly
属性不一定反映其属性状态。例如,在 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 及所有现代浏览器中都能工作),并且考虑到您别无选择,也必须实现服务器端验证,并且考虑到支持 pattern
和 required
的浏览器已经使用它们进行预提交验证——考虑到所有这些,真的还有必要添加另一个兼容性填充程序吗?
(此处可以添加关于实时验证的常见问题解答部分,内容与原文档中的FAQs部分相同)
以上是使用JavaScript即时表单验证的详细内容。更多信息请关注PHP中文网其他相关文章!