HTML5引入了几个新的属性来实现基于浏览器的表单验证。 pattern
属性是一个正则表达式,用于定义textarea
元素和大多数input
类型的有效输入范围。 required
属性表示是否必填字段。 对于不支持这些属性的传统浏览器,我们可以使用它们的值作为polyfill的基础。 我们还可以使用它们来提供更有趣的增强 – 即时表单验证。
基本概念
在最新版本的Firefox中,如果required
字段为空,或者其值与模式不匹配,那么该字段将显示一个红色的轮廓,如下图所示。
这当然不会立即发生。 如果是,则默认情况下,每个必填字段都将具有该轮廓。 相反,这些轮廓仅在您与该字段进行交互之后才会显示,这基本上类似于onchange
事件。
所以这就是我们要做的,使用onchange
作为触发事件。 作为替代方案,我们可以使用oninput
事件,一旦任何值被输入或粘贴到该字段中即可触发。 但是这真的太瞬间,因为它可以很容易地在许多类型的瞬间触发和快速连续打字,创造一个闪烁的效果,这将是令人讨厌的或不可能分散一些用户的注意力。 而且,在任何情况下,oninput
不会从程序化输入中触发,而onchange
也可能需要它来处理第三方附加组件的自动完成。
定义HTML和CSS
<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> <button name="preview" type="submit">Preview</button> <button name="save" type="submit">Submit Comment</button> </fieldset> </form>
这个例子是一个简单的评论表单,其中一些字段是必需的,一些是验证的,一些是两者都有。 带
required
的字段也会带aria-required
,为不了解新input
类型的辅助技术提供回退语义。
ARIA specification也定义了aria-invalid
属性。这就是我们将要用来指示字段何时无效(HTML5中没有等效属性)的属性。aria-invalid
属性提供了可访问信息,但它也可以用作CSS钩子来应用红色轮廓:
input[aria-invalid="true"], textarea[aria-invalid="true"] { border: 1px solid #f00; box-shadow: 0 0 4px 0 #f00; }
我们可以只使用
box-shadow
,而不是border
,坦率地说,这看起来更好,但是我们在有些浏览器中不支持不支持盒子阴影的指示,比如IE8。
添加JavaScript代码
现在我们有静态代码,我们可以添加脚本。 我们需要做的第一件事是添加一个addEvent()
函数:
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); }); } }
接下来,我们需要一个函数来确定一个给定的字段是否应该被验证,它只是测试它既不被禁用也不是只读,并且它具有
pattern
或required
属性:
function shouldBeValidated(field) { return ( !(field.getAttribute("readonly") || field.readonly) && !(field.getAttribute("disabled") || field.disabled) && (field.getAttribute("pattern") || field.getAttribute("required")) ); }
前两个条件可能看起来很冗长,但它们是必需的,因为元素的disabled
和readonly
属性不一定反映其属性状态。 例如,在Opera中,硬编码属性readonly="readonly"
的字段对于其readonly
属性仍将返回undefined
(点属性仅匹配通过脚本设置的状态)。
一旦有这些实用程序,我们可以定义主验证函数,该函数测试该字段,然后执行实际验证(如果适用):
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"); } } }
因此,如果一个字段是必需的,但没有值,或者它有一个模式和一个值,但该值与模式不匹配,则该字段无效。
由于pattern
已经定义了正则表达式的字符串形式,所以我们要做的就是将该字符串传递给RegExp
构造函数,并创建一个可以对该值进行测试的正则表达式对象。 但是,我们必须预先测试该值以确保它不为空,以便正则表达式本身不必考虑空字符串。
一旦我们确定一个字段是否无效,我们就可以控制它的aria-invalid
属性来指示该状态 – 将它添加到一个不具有该字段的无效字段中,或者从一个有效的字段中删除它。 简单! 最后,为了把这一切付诸实施,我们需要将验证函数绑定到一个onchange
事件。 应该如下:
addEvent(document, "change", function(e, target) { instantValidation(target); });
然而,
onchange
事件必须发泡(使用通常称为事件委托的技术),但在Internet Explorer 8和更早版本中,onchange
事件不会冒泡。 我们可以选择忽略这些浏览器,但我认为这将是一个耻辱,特别是当问题如此简单的解决方法。 它只是意味着一个更复杂的代码 – 我们必须获取input
和textarea
元素的集合,遍历它们,并将onchange
事件单独绑定到每个字段:
var fields = [ document.getElementsByTagName("input"), document.getElementsByTagName("textarea") ]; for (var a = fields.length, i = 0; i < a; i++) { for (var b = fields[i].length, j = 0; j < b; j++) { addEvent(fields[i][j], "change", function(e, target) { instantValidation(target); }); } }
原文:https://www.sitepoint.com/instant-validation/