HTML5引入了一些新属性来实现基于浏览器的表单验证。 pattern
属性是一个正则表达式,它定义了textarea
元素和大多数input
类型的有效输入范围。 required
属性指定是否需要一个字段。 对于未实现这些属性的旧版浏览器,我们可以将其值用作polyfill的基础。 我们还可以使用它们来提供更有趣的增强功能-即时表单验证。
我们在这里必须非常小心,不要被迷住,创建过于激进的验证,这会破坏自然的浏览行为并妨碍人们的使用。 例如,我见过一些表格,其中不可能用Tab键离开无效字段-使用JavaScript(或滥用 )强制焦点保持在字段内,直到有效为止。 这是非常差的可用性,并且直接违反了可访问性准则 。
我们在本文中要做的是减少干扰。 它甚至不是完整的客户端验证–只是一个微妙的可用性增强,以可访问的方式实现,(正如我在测试脚本时所发现的)几乎与Firefox现在所做的相同!
在最新版本的Firefox中,如果required
字段为空或其值与pattern
不匹配,则该字段将显示红色轮廓,如下图所示。
当然,这不会立即发生。 如果是这样,则默认情况下,每个必填字段都将具有该轮廓。 相反,这些轮廓仅在您与该字段进行交互后才显示,这基本上(尽管不完全准确)类似于onchange
事件。
这就是我们要做的,使用onchange
作为触发事件。 或者,我们可以使用oninput
事件,该事件在将任何值键入或粘贴到字段中时立即触发。 但这实在是太瞬时了,因为在键入时可以很容易地连续快速地触发许多类型的开关,从而产生闪烁的效果,这会使某些用户感到烦恼或无法分散他们的注意力。 而且,无论如何, oninput
不会从编程输入中触发,而onchange
会触发,因此我们可能需oninput
来处理第三方插件的自动完成之类的事情。
因此,让我们看一下我们的实现,从基于以下内容的HTML开始:
此示例是一个简单的注释表单,其中某些字段是必填字段,某些字段经过验证,而有些字段两者都是。 其中有场required
也有aria-required
,提供回退语义辅助技术的不理解新的input
类型。
ARIA规范还定义了一个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
,坦白地说,这样看起来会更好,但是在不支持box-shadows的浏览器(例如IE8)中,我们没有任何迹象。
现在我们有了静态代码,我们可以添加脚本了。 我们需要的第一件事是基本的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
(dot属性仅与通过脚本设置的状态匹配)。
一旦有了这些实用程序,就可以定义主要的验证功能,该功能将测试该字段,然后执行实际的验证(如果适用):
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
构造函数,这将创建一个我们可以针对该值进行测试的regex对象。 但是,我们必须预先测试该值以确保其不为空,以便正则表达式本身不必考虑空字符串。
一旦确定了一个字段是否无效,我们就可以控制其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);
});
}
}
因此,我们有了它–一种简单,非侵入式的即时表单验证增强功能,提供了可访问的视觉提示来帮助用户完成表单。 您可以在下面查看演示:
请参阅CodePen上的SitePoint ( @SitePoint )进行的笔即时表单验证 。
一旦执行了该脚本,我们实际上仅需要跳过和跳过完整的polyfill即可。 这样的脚本超出了本文的范围,但是如果您想进一步开发它,那么所有基本块都在这里–测试是否应验证字段,根据模式和/或要求验证字段以及绑定触发器事件。
我必须承认,我不确定这是否值得! 如果您已经有了此增强功能(在IE7以后的所有现代浏览器中都可以使用),并且除了实现服务器端验证之外别无选择 ,并且考虑到支持pattern
且required
使用浏览器的浏览器已经将它们用于预验证,提交验证–考虑到所有这些,是否真的有必要添加另一个polyfill?
From: https://www.sitepoint.com/instant-validation/