HTML5 给我们带来了很多非常好的优势。除了统一错误模型、引入新语义标签或简化文档类型等常见问题之外,最大的改进之一是表单的约束验证。如果没有表单,网络会是什么样子?
约束验证试图提高 Web 表单的可用性。浏览器可以直接告知用户无效值的可能性,而不是将表单发送到服务器,然后将其评估为无效,返回到客户端并最终由用户进行调整。这不仅减少了网络通信,还提高了页面的可用性。
需要注意的是,约束验证不能取代服务器端验证。此外,基于 JavaScript 的解决方案可能仍然有用。一般来说,我们总是必须实现服务器端验证。如果我们使用良好的架构,服务器上的模型约束将自动反映在传输的 HTML 代码中。这样我们就可以免费获得约束验证。现在我们可以使用 JavaScript 进一步增强体验,它既可以充当约束验证的补充,也可以充当填充。
我们将从非验证表单开始我们的旅程。然后我们将集成一个基于 JavaScript 的解决方案。最后介绍一下HTML5的约束验证。在最后一节中,我们将了解可能遇到的跨浏览器奇怪现象。
最经典的 HTML 表单版本是不带有任何客户端验证逻辑的版本。我们只需要提供一个标准的形式,不需要任何特殊的属性。正如简介中已经指出的,我们需要始终特别注意这种表单提交。
尽管我们确实希望保护客户端上已经存在的表单,但我们永远无法确定所提交数据的状态。保护和增强服务器上的表单验证的技术很大程度上取决于所使用的编程框架和语言。因此我们将跳过这样的讨论。相反,我们现在将讨论一般的表单提交。
在《精通HTML5》系列的第二部分中我们已经提到了表单编码类型的重要性。我们还研究了三种成熟的编码类型。剩下的问题是:这些价值观实际上是如何建立的?浏览器的确切行为取决于为 action
指定的协议。为了简单起见,我们现在假设 HTTP 或 HTTPS。
原则上,浏览器有两个选项:
两者的程序大致相同。简而言之,我们发现以下步骤:
表单数据集的构建意味着一些微妙的问题,但这些问题并不是很为人所知。例如,如果单击按钮来提交表单,情况就会有所不同。在这种情况下,按钮的值将传输到服务器。这可用于确定按下了哪个按钮。
如果我们按下第一个按钮,那么以下内容将被发送到服务器。
foo=bar
从 JavaScript 触发表单提交将导致不传输任何内容。 JavaScript 代码使用 HTMLFormElement
实例的 submit()
方法。
另一个有趣的方面是使用 image
类型提交输入元素的单击坐标。 image
输入类型不久前非常流行,人们认为检查用户点击的位置是个好主意。也许所显示的图像表明了几种可能性。然后服务器将负责评估用户的请求。
以下示例说明了此行为。
如果我们点击图片提交表单,就会考虑foo
的数据。仅当值存在时才会插入名称-值对。此外,我们需要命名输入元素,否则不会传输任何内容。
请求的内容可能类似于以下代码片段。
foo.x=71&foo.y=38&foo=bar
此外,我们应该注意不考虑禁用字段。这是有道理的。因此,下面的表格考虑了具有两个输入字段(一个启用和一个禁用)的前两个示例,可以构建为概念证明。
以编程方式提交表单将导致传输单个值。
即使没有约束验证或 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 键显式地移开焦点。
正如我们所看到的,顺序设置为首先触发 input
事件,然后触发 keyup
。其实这是有道理的。首先我们需要 keydown
,然后该值可能会发生变化,从而导致 input
事件。最后我们释放密钥,这会产生一个 keyup
事件。值得强调的是,input
仅在值发生变化时才会触发,而 keyup
与实际值变化无关。举个例子,如果我们按箭头键,我们只会看到 keyup
事件,而看不到 input
事件。
可以通过向所有表单字段添加事件侦听器来对所有元素进行实时验证。或者,我们只需要为表单添加一个用于 input
事件的事件侦听器。尽管非常优雅,但这种方法有一个明显的缺点。
考虑以下非常简单的 HTML:
我们使用 HTML5 form
属性在其外部声明 <form></form>
的一个字段。但是,input
事件正常工作,因为这些事件实际上会在 DOM 树中冒泡。因此,外部场触发的特定事件将不会被看到。
因此,最可靠的方法是获取表单并迭代 elements
集合中给出的子项。这里收集所有分配的字段(image
输入类型除外)。
约束验证意味着我们能够在 HTML 源代码中指定约束,然后浏览器使用这些约束来检查表单。有很多可能性。很多选项与输入类型相关,不能随意使用。在我们深入研究不同的验证和实现怪癖之前,让我们先简要了解一下整体设计。
所选择的 API 旨在使我们能够进行快速检查。我们可以探测当前实例是否能够通过单个 API 调用进行约束验证。
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
。如果颜色选择是 required
并且包含无效颜色,则颜色选择将验证为 valueMissing
。其他类型的反应类似。
其他可能的约束取决于输入的具体类型。类型决定了如何处理该值。是否将其视为文本?它代表一个数字吗?约束对其做出反应。
我们以date
输入类型为例。如果设置了有效日期,如果限制为 required
,我们会得到一个 valueMissing
。此外,如果实际输入了某些内容,则会设置 badInput
。但是,如果日期有效,我们可能会出现以下一个或多个验证错误:
rangeUnderflow
,如果日期低于 min
属性中指定的日期rangeOverflow
,如果日期高于 max
属性中指定的日期stepMismatch
,如果日期不满足提供的step
模式最后一点相当有趣。这里我们必须处理一种机制,该机制减去基数(可以是默认基数,也可以是 min 属性中提供的)并计算可以对步骤取模的数字。对于日期输入类型,计算并不完全明显。实际提供的日期类型是不同的。然而,从用户的角度来看,结果是有意义的。
对于文本输入,还有 pattern<code class="inline">pattern
属性,它允许我们指定用于验证的正则表达式。如果输入类型支持此约束,则会在失败时记录 patternMismatch
属性,它允许我们指定用于验证的正则表达式。如果输入类型支持此约束,则会在失败时记录 patternMismatch
约束验证使我们能够为用户(即使禁用了 JavaScript)提供有关当前表单状态的即时反馈。我们不必为了显示错误消息而浪费往返服务器的网络带宽。尽管如此,我们应该始终记住,表单提交通常是可以的。因此,在服务器端进行一些验证是不可避免的。
约束验证带来的可能性几乎是无限的。我们可以使用客户端验证来确保满足正则表达式,考虑日期和数字的有效范围,并选中某些复选框。我们还可以使用 JavaScript 扩展可用的检查。
以上是掌握HTML5:约束验证的详细内容。更多信息请关注PHP中文网其他相关文章!