![HTML5 Mastery系列图片](https://i-blog.csdnimg.cn/blog_migrate/f78d4e5ca5be816551a49747df8ecf8e.png)
HTML5给我们带来了很多真正的优势。 除了常见的可疑对象(如统一错误模型,新的语义标记或简化的文档类型)外,最大的改进之一是对表单的约束验证。 没有表单的网络将会是什么?
约束验证试图提高Web表单的可用性。 浏览器可以直接向用户通知无效值的可能性,而不是将表单发送到服务器,该表单随后将被评估为无效,然后返回给客户端并最终由用户进行调整。 这不仅减少了网络通信,而且还提高了页面的可用性。
重要的一点是,约束验证不能代替服务器端验证。 同样,基于JavaScript的解决方案可能仍然有用。 通常,我们总是必须实现服务器端验证。 如果我们使用良好的体系结构,则服务器上的模型约束将自动反映在传输HTML代码中。 这样我们就可以免费获得约束验证。 现在,我们可以使用JavaScript来进一步增强体验,JavaScript可以作为约束验证的补充,也可以作为polyfill。
我们将以非验证表格开始我们的旅程。 然后,我们将集成一个基于JavaScript的解决方案。 最后,我们将介绍HTML5的约束验证。 在上一节中,我们将介绍可能遇到的跨浏览器异常情况。
提交非验证表格
HTML表单的最经典版本是不带有任何客户端验证逻辑的版本。 我们只需要提供没有任何特殊属性的标准表格即可。 正如引言中已经提到的那样,我们始终需要特别注意这种表单提交。
即使我们确实想在客户端保护我们的表单,我们也无法确定提交数据的状态。 保护和增强服务器上的表单验证的技术高度依赖于所使用的编程框架和语言。 因此,我们将跳过这样的讨论。 相反,我们现在将讨论一般的表单提交。
在“ HTML5精通”系列的第二部分中,我们已经提到了表单编码类型的重要性。 我们还研究了三种公认的编码类型。 剩下的问题是:值是如何实际构建的? 浏览器的确切行为取决于为action
指定的协议。 现在我们假设使用HTTP或HTTPS来保持简单。
原则上,浏览器有两个选项:
- 更改操作以携带表单的值。
- 通过请求的正文提交值。
两者共享大约相同的过程。 简而言之,我们发现以下步骤:
- 使用正确的编码构建数据集。
- 创建具有数据集和编码类型的请求。
- 发送请求。
表单数据集的构造隐含了一些细微的问题,这些问题并不是很为人所知。 例如,如果单击了按钮以提交表单,则会有所不同。 在这种情况下,按钮的值将传输到服务器。 这可以用来确定按下了哪个按钮。
如果我们按第一个按钮,则以下内容将发送到服务器。
foo=bar
从JavaScript触发表单提交将导致不传输任何内容。 JavaScript代码使用HTMLFormElement
实例的HTMLFormElement
submit()
方法。
另一个有趣的方面是提交具有image
类型的输入元素的点击坐标。 image
输入类型在不久前非常流行,人们认为检查用户单击位置是一个好主意。 也许显示的图像表明了几种可能性。 然后,服务器将负责评估用户的请求。
下面的示例说明了此行为。
如果单击图像提交表单,将考虑foo
的数据。 仅当值存在时才插入名称-值对。 另外,我们需要命名输入元素,否则将不会传输任何内容。
然后,请求的内容可能类似于以下代码片段。
foo.x=71&foo.y=38&foo=bar
此外,我们应该意识到,不会考虑禁用字段。 这很有道理。 因此,可以考虑以下形式,该形式考虑具有两个输入字段(一个启用和一个禁用)的前两个示例,作为概念证明。
![表格提交](https://i-blog.csdnimg.cn/blog_migrate/1ed6ce30cb56cdbc0fbb016fe27fff38.png)
以编程方式提交表单将导致发送单个值。
基本表格验证
即使没有约束验证或JavaScript,浏览器也已经为我们提供了一些简单的表单验证。 正如我们之前所看到的,考虑了表单的状态(例如启用或禁用)和提交者。 但是,所有这些都不会阻止表单的提交。 一种简单的方法是编写一些JavaScript,以防止可能中止该过程。
JavaScript的第一种用法实际上是为表单提供增强的功能。 基本想法是,一旦要提交表单,便会通过事件得到通知。 此时,我们可以检查所有值并中止该过程。 当然,我们可以完善整个构想,以便在任何值发生更改时始终进行检查。 尽管如此,最终,根据我们的上一次评估,我们可能会中止提交。
var form = document.querySelector('form');
form.addEventListener('submit', function (ev) {
// always abort!
ev.preventDefault();
}, false);
理论上,进行实时验证很容易。 但是,指定的DOM事件的工作方式可能与直观猜测的工作方式不同。 例如,仅在文本框失去焦点之后才触发文本框的change
事件。 当用户单击提交按钮时,可能会发生这种情况。 因此,与验证的交互被中断并且感觉不到实时。
相反,使用keyup
或input
事件是有意义的。 对于文本框,前者是一个可行的解决方案,而后者适用于所有输入元素(符合预期)。 唯一的限制是它已随HTML5引入,某些较旧的浏览器可能不支持。
考虑到这一点,让我们比较各种事件以查看执行顺序。 以下测试代码对我们有帮助。
var input = document.querySelector('input');
['input', 'keyup', 'change'].forEach(function (eventName) {
input.addEventListener(eventName, function (e) {
console.log(eventName + ' event triggered');
}, false);
});
对于我们的测试<input>
元素,当用几个字母进行探测时,我们看到以下结果。 最后,我们使用Tab键明确地将焦点移开。
![输入事件HTML5](https://i-blog.csdnimg.cn/blog_migrate/94cad3af8505a366f97ce038719286cf.gif)
如我们所见,顺序设置为先触发input
事件,然后触发keyup
。 其实这是有道理的。 首先,我们需要keydown
,然后值可能已更改,从而导致input
事件。 最后,我们释放密钥,这会产生一个keyup
事件。 值得强调的是,只有在值更改时才触发input
,而keyup
不依赖于实际值更改。 举个例子,如果我们按方向键,我们只会看到keyup
事件,但没有input
事件。
通过向所有表单字段添加事件侦听器,可以对所有元素进行实时验证。 或者,我们只需要为表单的input
事件添加一个事件侦听器。 尽管非常优雅,但此方法仍存在重大缺陷。
考虑以下非常简单HTML:
<form id=main></form><input form=main>
我们使用HTML5 form
属性在其外部声明<form>
一个字段。 但是, input
事件才起作用,因为这些事件实际上会冒泡DOM树。 因此,将不会看到由外界触发的特定事件。
因此,最可靠的方法是获取表单并遍历elements
集合中给定的子代。 此处收集所有分配的字段( image
输入类型除外)。
约束验证
约束验证意味着我们能够在HTML源代码中指定约束,然后浏览器将其用于检查表单。 有很多可用的可能性。 许多选项与输入类型有关,不能任意使用。 在深入探讨不同的验证和实现怪癖之前,让我们简要了解一下总体设计。
选择的API旨在使我们能够进行快速检查。 我们可以探查当前实例是否能够通过单个API调用进行约束验证。
![HTML约束验证架构](https://i-blog.csdnimg.cn/blog_migrate/170c7541db7055be833ad1154222153c.png)
该API也相当开放,因此我们可以查询浏览器获得的结果或扩展浏览器的结果。 伪接口Validation
也被其他接口继承,不仅是HTMLInputElement
。
让我们看一些示例代码。 在以下代码中,我们首先检查是否完全可以进行表单验证。 如果是这样,那么我们会关心type=date
字段的验证结果。 如果用户选择了有效日期,我们将检查复选框的状态。
var form = document.querySelector('form');
var date = document.querySelector('#birthday');
if (form.willValidate) {
if (!date.validity.valid || checkbox.checked)
checkbox.setCustomValidity('');
else
checkbox.setCustomValidity('You need to agree to our terms.');
}
这种条件逻辑(仅在某些情况下有效)不能仅使用标记来实现。 但是我们可以将自定义逻辑与集成功能很好地结合在一起。
HTML5知道很多不同的输入类型。 但毕竟它们可以分为三类:
- 文本
- 数
- 日期
从value
属性看不到差异。 在这里,我们总是得到string
值。 毕竟,该值将以文本形式提交。 具有这三个组的结果是关于某些类型的约束的不同行为。
以下约束几乎总是以相同的方式起作用:
-
required
,如果value
的长度为零,则导致valueMissing
-
minlength
,导致tooShort
如果字符串的长度太短 -
maxlength
,如果字符串的长度太长,则导致tooLong
当然,也有例外。 例如,复选框对required
checked
要求作出反应。 颜色的选择将验证到valueMissing
如果required
且包含一个无效的颜色。 其他类型的反应类似。
其他可能的约束条件取决于输入的特定类型。 类型确定如何处理该值。 它像文本一样对待吗? 它代表数字吗? 约束对此作出反应。
让我们以date
输入类型为例。 如果设置了有效日期,则如果限制为required
则将获得valueMissing
。 另外,如果实际输入badInput
则设置badInput
。 但是,在有效日期的情况下,我们可能会出现以下一个或多个验证错误:
-
rangeUnderflow
,如果日期低于min
属性中指定的日期 -
rangeOverflow
,如果日期大于max
属性中指定的日期 -
stepMismatch
,如果日期不满足提供的step
模式
最后一点很有趣。 在这里,我们必须处理一种机制,该机制减去基数(默认基数或min
属性中提供的基数),然后计算可以以该步数为模的数字。 对于日期输入类型,该计算并不完全明显。 实际提供哪种日期会有所不同。 但是,从用户的角度来看,结果是有意义的。
对于文本输入,还有pattern
属性,该属性允许我们指定用于验证的正则表达式。 如果输入类型支持此约束,则在失败的情况下会记录patternMismatch
。
结论
约束验证使我们能够向用户(即使使用了禁用JavaScript)也可以立即反馈有关当前表单状态的信息。 我们不必浪费去往服务器的网络带宽,而只是显示一条错误消息。 尽管如此,我们应该始终牢记总体上可以提交表单。 因此,在服务器端进行一些验证是不可避免的。
约束验证附带的可能性几乎是无限的。 我们可以使用客户端验证来确保满足正则表达式,考虑日期和数字的有效范围,并选中某些复选框。 我们还可以使用JavaScript扩展可用的检查。
翻译自: https://code.tutsplus.com/tutorials/html5-mastery-constraint-validation--cms-24844