【H5】16 表单 其五 表单验证

在将数据提交到服务器之前,重要的是确保以正确的格式填写所有必需的表单控件。这称为客户端表单验证,可帮助确保所提交的数据符合各种表单控件中规定的要求。本文将引导您通过基本概念和客户端表单验证示例。

先决条件: 计算机知识,对HTMLCSSJavaScript有一定的了解
目的: 要了解什么是客户端表单验证,为什么重要,以及如何应用各种技术来实现它。

客户端验证是初步检查,是良好用户体验的重要特征;通过在客户端捕获无效数据,用户可以立即对其进行修复。

如果到达服务器然后被拒绝,则往返服务器的往返时间将导致明显的延迟,然后再返回客户端以告知用户修复其数据。

但是,不应将客户端验证视为详尽的安全措施!您的应用应始终对服务器端 客户端上任何表单提交的数据执行安全检查,因为客户端验证太容易被绕开,因此恶意用户仍然可以轻松地将不良数据发送到您的服务器。

阅读网站安全性以了解可能发生的情况;实现服务器端验证在某种程度上超出了本模块的范围,但是您应该牢记这一点。


 

什么是表格验证?

转到带有注册表格的任何受欢迎的网站,您会发现,

当您不以期望的格式输入数据时,它们会提供反馈。您会收到以下消息:

  • “此字段为必填项”(您不能将此字段留空)。
  • “请以xxx-xxxx格式输入您的电话号码”(必须使用特定的数据格式才能被视为有效)。
  • “请输入有效的电子邮件地址”(您输入的数据格式不正确)。
  • “您的密码长度必须介于8到30个字符之间,并包含一个大写字母,一个符号和一个数字。” (您的数据需要非常特定的数据格式)。

这称为表单验证

当您输入数据时,浏览器和/或Web服务器将检查以确保数据格式正确且在应用程序设置的限制内。

在浏览器中完成的验证称为客户端验证,而在服务器上完成的验证称为服务器端验证。

 

在本章中,我们着重于客户端验证。

如果信息格式正确,则应用程序允许将数据提交到服务器并(通常)保存在数据库中;

如果信息的格式不正确,则会向用户显示一条错误消息,说明需要更正的内容,然后让他们重试。

 

我们希望尽可能轻松地填写Web表单。

那么为什么我们要坚持验证我们的表格呢?

主要有以下三个原因:

  • 我们希望以正确的格式获取正确的数据。 如果我们的用户数据以错误的格式存储,不正确或被完全省略,则我们的应用程序将无法正常运行。
  • 我们要保护用户的数据强制我们的用户输入安全密码可以更轻松地保护他们的帐户信息。
  • 我们要保护自己恶意用户可以通过多种方式滥用不受保护的表单来破坏应用程序(请参阅网站安全性)。

    警告:永远不要信任从客户端传递到服务器的数据。即使您的表单可以正确验证并防止客户端输入错误,恶意用户仍然可以更改网络请求。


 

不同类型的客户端验证

您将在网上遇到两种不同类型的客户端验证:

  • 内置的表单验证使用HTML5表单验证功能,我们已在本模块的许多地方进行了讨论。此验证通常不需要太多JavaScript。内置的表单验证比JavaScript具有更好的性能,但是不像JavaScript验证那样​​可自定义。
  • JavaScript验证使用JavaScript进行编码。该验证是完全可定制的,但是您需要全部创建(或使用一个库)。

 

使用内置的表单验证

HTML5表单控件的最重要功能之一就是无需依赖JavaScript即可验证大多数用户数据的能力。

这是通过在表单元素上使用验证属性来完成的。在课程的早期,我们已经看到了许多这样的内容,但请回顾一下:

  • required:指定在提交表单之前是否需要填写表单字段。
  • minlengthmaxlength:指定文本数据(字符串)的最小和最大长度
  • minmax:指定数字输入类型的最小值和最大值
  • type:指定数据是数字,电子邮件地址还是其他特定的预设类型。 
  • pattern:指定正则表达式正则表达式定义输入的数据需要遵循的模式。

 

如果在表单字段中输入的数据遵循上述属性指定的所有规则,则将其视为有效。如果不是,则认为它无效。

当一个元素有效时,以下情况成立:

  • 该元素与:validCSS伪类匹配,从而使您可以将特定样式应用于有效元素。
  • 如果用户尝试发送数据,则浏览器将提交该表单,前提是没有其他阻止它发送的表单(例如JavaScript)。

 

当元素无效时,以下情况成立:

  • 该元素与:invalidCSS伪类匹配,有时还与其他UI伪类(例如:out-of-range匹配具体取决于错误,这使您可以将特定样式应用于无效元素。
  • 如果用户尝试发送数据,浏览器将阻止该表单并显示错误消息。

:有几个错误,这将阻止表单被提交,其中包括

badInput

patternMismatch

rangeOverflowrangeUnderflow

stepMismatch

tooLongtooShort

typeMismatch

valueMissing

customError


 

内置表单验证示例

在本节中,我们将测试上面讨论的一些属性。

简单的开始文件

让我们从一个简单的示例开始:

一个输入,您可以选择喜欢香蕉还是樱桃。

此示例涉及<input>带有关联<label>和提交的简单文本<button>

在GitHub上的fruit-start.html上找到源代码,   并在下面提供一个实时示例。

<form>
  <label for="choose">Would you prefer a banana or cherry?</label>
  <input id="choose" name="i_like">
  <button>Submit</button>
</form>

 

input:invalid {
  border: 2px dashed red;
}

input:valid {
  border: 2px solid black;
}

 

首先,fruit-start.html在硬盘驱动器上的新目录中复制的副本


 

必填属性

最简单的HTML5验证功能是required属性。

要强制输入,请将此属性添加到元素。

设置此属性后,该元素与:requiredUI伪类匹配,并且表单不会提交,当输入为空时,提交时会显示错误消息。

如果为空,则与:invalidUI伪类匹配的输入也将被视为无效

required属性添加到您的输入中,如下所示。

<form>
  <label for="choose">Would you prefer a banana or cherry? (required)</label>
  <input id="choose" name="i_like" required>
  <button>Submit</button>
</form>

 

请注意示例文件中包含的CSS:

input:invalid {
  border: 2px dashed red;
}

input:invalid:required {
  background-image: linear-gradient(to right, pink, lightgreen);
}

input:valid {
  border: 2px solid black;
}

 

此CSS会使输入无效时输入具有红色虚线边框,而有效时则使输入具有更细的黑色实线边框。

当需要输入输入无效时,我们还添加了背景渐变在下面的示例中尝试新行为:

 

注意:您可以在GitHub上以fruit-validation.html的形式找到此示例(另请参见源代码。)

尝试提交没有价值的表格。

请注意无效输入如何获得焦点,出现默认错误消息(“请填写此字段”),并阻止发送表单。

required任何支持该属性的元素上都存在该属性,这意味着该元素:required无论是否具有值都伪类匹配如果<input>没有值,input则将与:invalid伪类匹配

注意:为了获得良好的用户体验,请在需要表单字段时向用户指示。

WCAG 可访问性指南要求这不仅是良好的用户体验

另外,仅要求用户输入您实际需要的数据:例如,为什么您真的需要知道某人的性别或头衔?


 

针对正则表达式进行验证

另一个有用的验证功能是pattern属性,该属性期望使用正则表达式作为其值。正则表达式(regex)是一种可用于匹配文本字符串中字符组合的模式,因此正则表达式非常适合表单验证,并可以在JavaScript中用于多种其他用途。

正则表达式非常复杂,我们不打算在本文中详尽地教您。以下是一些示例,可让您基本了解它们的工作原理。

  • a—匹配一个字符a(不是b,不是aa,依此类推)。
  • abc-匹配a,然后是b,然后是c
  • ab?c—匹配a,可选后跟单个b,后跟cacabc
  • ab*c-匹配a,可选地后跟任意数量的bs,后跟cacabcabbbbbc,等等)。
  • a|b—匹配一个为a或的字符b
  • abc|xyz-完全配对abc或正好xyz(但不abcxyz 或ay,等等)。

在此我们不讨论更多的可能性。有关完整列表和许多示例,请查阅我们的正则表达式文档。

让我们实现一个例子。更新您的HTML以添加如下pattern属性:

<form>
  <label for="choose">Would you prefer a banana or a cherry?</label>
  <input id="choose" name="i_like" required pattern="[Bb]anana|[Cc]herry">
  <button>Submit</button>
</form>

 

这为我们提供了以下更新-试用:

 

注意:您可以在GitHub上以fruit-pattern.html的形式找到此示例(另请参见源代码。)

在此示例中,该<input>元素接受四个可能值之一:字符串“香蕉”,“香蕉”,“樱桃”或“樱桃”。正则表达式区分大小写,但是我们使用嵌套在方括号内的额外“ Aa”模式使它支持大写和小写形式。

此时,请尝试将pattern属性内的值更改为等于您先前看到的一些示例,并查看其如何影响您可以输入的值以使输入值有效。尝试自己编写一些内容,然后看看它如何进行。尽可能使它们与水果相关,以便您的示例有意义!

如果的非空值<input>与正则表达式的模式不匹配,则input将会与:invalid伪类匹配

注意:某些<input>元素类型不需要pattern针对正则表达式验证属性。email例如,指定类型可根据格式正确的电子邮件地址模式或与具有逗号分隔的电子邮件地址列表(如果具有multiple属性)相匹配的模式来验证输入值  

注意<textarea>元素不支持该pattern属性。


 

限制您输入的时间

您可以限制通过<input><textarea>使用  minlengthmaxlength属性创建的所有文本字段的字符长度

如果字段具有值并且该值的字符数少于该minlength值或字符数大于该,则该字段无效maxlength

浏览器通常不允许用户在文本字段中输入比预期更长的值。

与仅使用一种更好的用户体验相比maxlength,它还以一种可访问的方式提供字符计数反馈,并让他们按比例缩小其内容。

例如,在Twitter上发推时看到的字符限制。

JavaScript(包括使用的解决方案maxlength)可用于提供此功能


 

限制条目的值

对于数字字段(即<input type="number">),minmax属性可用于提供一系列有效值。如果该字段包含的值超出此范围,则它将无效。

让我们看另一个例子。创建fruit-start.html文件的新副本

现在删除<body>元素的内容,并用以下内容替换它:

<form>
  <div>
    <label for="choose">Would you prefer a banana or a cherry?</label>
    <input type="text" id="choose" name="i_like" required minlength="6" maxlength="6">
  </div>
  <div>
    <label for="number">How many would you like?</label>
    <input type="number" id="number" name="amount" value="1" min="1" max="10">
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>

 

  • 在这里,您将看到我们给了text字段a minlengthmaxlength6,与香蕉和樱桃的长度相同。
  • 我们还给了number字段a min和a max十。输入的数字超出此范围将显示为无效;用户将无法使用递增/递减箭头将值移到该范围之外。如果用户手动输入此范围之外的数字,则数据无效。该数字不是必需的,因此删除该值仍将得到一个有效值。

这是实时运行的示例:

 

注意:您可以在GitHub上以fruit-length.html的形式找到此示例(另请参见源代码。)

注意:(<input type="number">以及其他类型,例如  rangedate)也可以采用  step属性,该属性指定当使用输入控件(例如上下数字按钮)时,值将递增或递减的增量。在上面的示例中,我们没有包含step属性,因此该值默认为1这意味着浮点数(如3.2)也将显示为无效。


 

完整的例子

这是一个完整的示例,显示HTML的内置验证功能的用法。首先,一些HTML:

<form>
  <p>
    <fieldset>
      <legend>Do you have a driver's license?<abbr title="This field is mandatory" aria-label="required">*</abbr></legend>
      <!-- While only one radio button in a same-named group can be selected at a time,
           and therefore only one radio button in a same-named group having the "required"
           attribute suffices in making a selection a requirement --> 
      <input type="radio" required name="driver" id="r1" value="yes"><label for="r1">Yes</label>
      <input type="radio" required name="driver" id="r2" value="no"><label for="r2">No</label>
    </fieldset>
  </p>
  <p>
    <label for="n1">How old are you?</label>
    <!-- The pattern attribute can act as a fallback for browsers which
         don't implement the number input type but support the pattern attribute.
         Please note that browsers that support the pattern attribute will make it
         fail silently when used with a number field.
         Its usage here acts only as a fallback -->
    <input type="number" min="12" max="120" step="1" id="n1" name="age"
           pattern="\d+">
  </p>
  <p>
    <label for="t1">What's your favorite fruit?<abbr title="This field is mandatory" aria-label="required">*</abbr></label>
    <input type="text" id="t1" name="fruit" list="l1" required
           pattern="[Bb]anana|[Cc]herry|[Aa]pple|[Ss]trawberry|[Ll]emon|[Oo]range">
    <datalist id="l1">
      <option>Banana</option>
      <option>Cherry</option>
      <option>Apple</option>
      <option>Strawberry</option>
      <option>Lemon</option>
      <option>Orange</option>
    </datalist>
  </p>
  <p>
    <label for="t2">What's your e-mail address?</label>
    <input type="email" id="t2" name="email">
  </p>
  <p>
    <label for="t3">Leave a short message</label>
    <textarea id="t3" name="msg" maxlength="140" rows="5"></textarea>
  </p>
  <p>
    <button>Submit</button>
  </p>
</form>

 

现在使用一些CSS样式化HTML:

form {
  font: 1em sans-serif;
  max-width: 320px;
}

p > label {
  display: block;
}

input[type="text"],
input[type="email"],
input[type="number"],
textarea,
fieldset {
  width : 100%;
  border: 1px solid #333;
  box-sizing: border-box;
}

input:invalid {
  box-shadow: 0 0 5px 1px red;
}

input:focus:invalid {
  box-shadow: none;
}

 

结果如下:

 

有关可用于约束输入值和支持它们的输入类型的属性的完整列表,请参见与验证相关的属性

注意:您可以在GitHub上找到该示例,网址为full-example.html(另请参见源代码。)


 

使用JavaScript验证表单

如果要控制本机错误消息的外观或处理不支持HTML内置表单验证的旧版浏览器,则必须使用JavaScript。在本节中,我们将介绍执行此操作的不同方法。

约束验证API

大多数浏览器都支持Constraint Validation API,该API由以下表单元素DOM接口上可用的一组方法和属性组成:

约束验证API在上述元素上提供了以下属性。

  • validationMessage:返回描述该控件不满足的验证约束(如果有)的本地化消息。如果控件不是约束验证的候选对象(willValidateis false)或元素的值满足其约束条件(有效),则将返回一个空字符串。
  • validity:返回一个ValidityState对象,对象包含几个描述元素有效性状态的属性。您可以在ValidityState参考页面中找到所有可用属性的完整详细信息下面列出了一些较常见的:
    • patternMismatchtrue如果该值不匹配指定的pattern,并且匹配,则返回false如果为true,则元素匹配:invalidCSS伪类。
    • tooLongtrue如果值大于maxlength属性指定的最大长度,或者false小于或等于最大长度,则返回如果为true,则元素匹配:invalidCSS伪类。
    • tooShorttrue如果值小于minlength属性指定的最小长度,或者false大于或等于最小长度,则返回如果为true,则元素匹配:invalidCSS伪类。
    • rangeOverflowtrue如果该值大于max属性指定的最大值,或者false小于或等于最大值,则返回。如果为true,则元素与:invalid:out-of-range伪类匹配
    • rangeUnderflowtrue如果值小于min属性指定的最小值,或者false大于或等于最小值,则返回。如果为true,则元素与:invalid:out-of-range伪类匹配
    • typeMismatch:返回true值是否不是必需的语法(当typeemail或时url),或者false语法正确。如果为true,则元素与:invalidCSS伪类匹配
    • validtrue如果元素满足其所有验证约束,因此被认为是有效的,或者false它未通过任何约束,则返回。如果为true,则元素匹配:validCSS伪类;否则为false :invalid否则CSS伪类。
    • valueMissing:返回true该元素是否具有required属性,但没有值,false否则返回。如果为true,则元素匹配:invalidCSS伪类。
  • willValidate:返回true在提交表单时是否将验证元素;false除此以外。

约束验证API还可在上述元素上提供以下方法。

  • checkValidity()true如果元素的值没有有效性问题,则返回;否则,返回0 false除此以外。如果该元素无效,则此方法还会在该元素上触发一个invalid事件
  • setCustomValidity(message):向元素添加自定义错误消息;如果设置了自定义错误消息,则认为该元素无效,并显示指定的错误。这使您可以使用JavaScript代码建立验证失败,而不是由标准HTML5验证约束提供的验证失败。报告问题时,该消息将显示给用户。

实施自定义错误消息

正如您在前面的HTML5验证约束示例中所看到的,每次用户尝试提交无效的表单时,浏览器都会显示一条错误消息。此消息的显示方式取决于浏览器。

这些自动消息有两个缺点:

  • 没有标准的方法来更改CSS的外观。
  • 它们取决于浏览器的语言环境,这意味着您可以使用一种语言显示页面,而用另一种语言显示错误消息,如以下Firefox屏幕截图所示。

在英语页面上用法语显示的Firefox错误消息示例

自定义这些错误消息是约束验证API的最常见用例之一让我们来看一个简单的示例。

我们将从一些简单的HTML开始(随意将其放在空白HTML文件中;如果愿意,可以使用fruit-start.html的新副本作为基础):

<form>
  <label for="mail">I would like you to provide me with an e-mail address:</label>
  <input type="email" id="mail" name="mail">
  <button>Submit</button>
</form>

并将以下JavaScript添加到页面:

const email = document.getElementById("mail");

email.addEventListener("input", function (event) {
  if (email.validity.typeMismatch) {
    email.setCustomValidity("I am expecting an e-mail address!");
  } else {
    email.setCustomValidity("");
  }
});

 

在这里,我们存储对电子邮件输入的引用,然后向其中添加一个事件侦听器,该事件侦听器在每次更改输入内部的值时运行包含的代码。

在包含的代码内部,我们检查电子邮件输入的validity.typeMismatch属性是否返回true,这意味着包含的值与格式正确的电子邮件地址的模式不匹配。如果是这样,我们将setCustomValidity()通过自定义消息调用该方法。这将使输入无效,因此当您尝试提交表单时,提交将失败并显示自定义错误消息。

如果validity.typeMismatch属性返回false,则将setCustomValidity()方法称为空字符串。这将使输入有效,因此将提交表单。

您可以在下面尝试:

 

注意:您可以在GitHub上以custom-error-message.html的形式找到此示例(另请参见源代码。)


 

更详细的例子

现在,我们已经看到了一个非常简单的示例,让我们看看如何使用此API构建一些稍微复杂的自定义验证。

首先是HTML。再次,随时与我们一起构建它:

<form novalidate>
  <p>
    <label for="mail">
      <span>Please enter an email address:</span>
      <input type="email" id="mail" name="mail" required minlength="8">
      <span class="error" aria-live="polite"></span>
    </label>
  </p>
  <button>Submit</button>
</form>

这种简单的形式使用novalidate属性来关闭浏览器的自动验证。这使我们的脚本可以控制验证。但是,这不会禁用对约束验证API的支持,也不会禁用CSS伪类(如:valid等)的应用。这意味着,即使浏览器在发送数据之前不会自动检查表单的有效性,您仍然可以自己做,并相应地设置表格样式。

我们要验证的输入是<input type="email">,为required,具有minlength8个字符。让我们使用自己的代码进行检查,并为每个代码显示一条自定义错误消息。

我们旨在显示<span>元素内部的错误消息在该aria-live属性上设置属性是<span>为了确保将我们的自定义错误消息显示给所有人,包括将其读出给屏幕阅读器用户。

注意:这里的关键是,novalidate在表单上设置属性是阻止表单显示其自身的错误消息气泡的方法,并允许我们以自己选择的方式在DOM中显示自定义错误消息。

现在使用一些基本的CSS来稍微改善表单的外观,并在输入数据无效时提供一些视觉反馈:

body {
  font: 1em sans-serif;
  width: 200px;
  padding: 0;
  margin : 0 auto;
}

p * {
  display: block;
}

input[type=email]{
  -webkit-appearance: none;
  appearance: none;

  width: 100%;
  border: 1px solid #333;
  margin: 0;

  font-family: inherit;
  font-size: 90%;

  box-sizing: border-box;
}

/* This is our style for the invalid fields */
input:invalid{
  border-color: #900;
  background-color: #FDD;
}

input:focus:invalid {
  outline: none;
}

/* This is the style of our error messages */
.error {
  width  : 100%;
  padding: 0;

  font-size: 80%;
  color: white;
  background-color: #900;
  border-radius: 0 0 5px 5px;

  box-sizing: border-box;
}

.error.active {
  padding: 0.3em;
}

 

现在,让我们看一下实现自定义错误验证的JavaScript。

// There are many ways to pick a DOM node; here we get the form itself and the email
// input box, as well as the span element into which we will place the error message.
const form  = document.getElementsByTagName('form')[0];

const email = document.getElementById('mail');
const emailError = document.querySelector('#mail + span.error');

email.addEventListener('input', function (event) {
  // Each time the user types something, we check if the
  // form fields are valid.

  if (email.validity.valid) {
    // In case there is an error message visible, if the field
    // is valid, we remove the error message.
    emailError.innerHTML = ''; // Reset the content of the message
    emailError.className = 'error'; // Reset the visual state of the message
  } else {
    // If there is still an error, show the correct error
    showError();
  }
});

form.addEventListener('submit', function (event) {
  // if the email field is valid, we let the form submit

  if(!email.validity.valid) {
    // If it isn't, we display an appropriate error message
    showError();
    // Then we prevent the form from being sent by canceling the event
    event.preventDefault();
  }
});

function showError() {
  if(email.validity.valueMissing) {
    // If the field is empty
    // display the following error message.
    emailError.textContent = 'You need to enter an e-mail address.';
  } else if(email.validity.typeMismatch) {
    // If the field doesn't contain an email address
    // display the following error message.
    emailError.textContent = 'Entered value needs to be an e-mail address.';
  } else if(email.validity.tooShort) {
    // If the data is too short
    // display the following error message.
    emailError.textContent = `Email should be at least ${ email.minLength } characters; you entered ${ email.value.length }.`;
  }

  // Set the styling appropriately
  emailError.className = 'error active';
}

 

这些评论很好地解释了事情,但是简短地:

  • 每次我们更改输入的值时,我们都会检查它是否包含有效数据。如果有,我们将删除所有显示的错误消息。如果数据无效,我们将运行showError()以显示适当的错误。
  • 每次我们尝试提交表单时,我们都会再次检查数据是否有效。如果是这样,我们让表单提交。如果没有,我们将运行showError()以显示适当的错误,并使用停止提交表单preventDefault()
  • showError()函数使用输入validity对象的各种属性来确定错误是什么,然后适当地显示错误消息。

这是实时结果:

 

注意:您可以在GitHub上找到此示例,网址为detail-custom-validation.html(另请参见源代码。)

约束验证API为您提供了一个强大的工具来处理表单验证,使您对用户界面具有极大的控制权,而不仅仅是单独使用HTML和CSS所能做的。

注意:有关更多信息,请参阅我们的约束验证指南约束验证API参考。


 

在没有内置API的情况下验证表单

在某些情况下,例如旧版浏览器支持或自定义控件,您将无法使用或不想使用Constraint Validation API。您仍然可以使用JavaScript来验证表单,但您只是必须自己写。

要验证表单,请问自己几个问题:

我应该执行哪种验证?
您需要确定如何验证数据:字符串操作,类型转换,正则表达式等。由你决定。
如果表单不通过验证该怎么办?
这显然是UI问题。您必须决定表单的行为方式。表格是否仍发送数据?您应该突出显示错误的字段吗?您应该显示错误消息吗?
如何帮助用户更正无效数据?
为了减少用户的挫败感,提供尽可能多的有用信息以指导他们纠正输入很重要。您应该提供前期建议,以便他们知道预期的结果,并清除错误消息。如果您想深入了解表单验证UI要求,请阅读以下有用的文章:

 

一个不使用约束验证API的示例

为了说明这一点,以下是与旧版浏览器一起使用的上一示例的简化版本。

HTML几乎是相同的。我们只是删除了HTML验证功能。

<form>
  <p>
    <label for="mail">
        <span>Please enter an email address:</span>
        <input type="text" class="mail" id="mail" name="mail">
        <span class="error" aria-live="polite"></span>
    </label>
  </p>
  <!-- Some legacy browsers need to have the `type` attribute
       explicitly set to `submit` on the `button`element -->
  <button type="submit">Submit</button>
</form>

 

同样,CSS不需要太多更改。我们刚刚将:invalidCSS伪类变成了真实类,并避免使用在Internet Explorer 6上不起作用的属性选择器。

body {
  font: 1em sans-serif;
  width: 200px;
  padding: 0;
  margin : 0 auto;
}

form {
  max-width: 200px;
}

p * {
  display: block;
}

input.mail {
  -webkit-appearance: none;

  width: 100%;
  border: 1px solid #333;
  margin: 0;

  font-family: inherit;
  font-size: 90%;

  box-sizing: border-box;
}

/* This is our style for the invalid fields */
input.invalid{
  border-color: #900;
  background-color: #FDD;
}

input:focus.invalid {
  outline: none;
}

/* This is the style of our error messages */
.error {
  width  : 100%;
  padding: 0;
 
  font-size: 80%;
  color: white;
  background-color: #900;
  border-radius: 0 0 5px 5px;
  box-sizing: border-box;
}

.error.active {
  padding: 0.3em;
}

 

最大的变化在于JavaScript代码,这需要做很多繁重的工作。

// There are fewer ways to pick a DOM node with legacy browsers
const form  = document.getElementsByTagName('form')[0];
const email = document.getElementById('mail');

// The following is a trick to reach the next sibling Element node in the DOM
// This is dangerous because you can easily build an infinite loop.
// In modern browsers, you should prefer using element.nextElementSibling
let error = email;
while ((error = error.nextSibling).nodeType != 1);

// As per the HTML5 Specification
const emailRegExp = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;

// Many legacy browsers do not support the addEventListener method.
// Here is a simple way to handle this; it's far from the only one.
function addEvent(element, event, callback) {
  let previousEventCallBack = element["on"+event];
  element["on"+event] = function (e) {
    const output = callback(e);

    // A callback that returns `false` stops the callback chain
    // and interrupts the execution of the event callback.
    if (output === false) return false;

    if (typeof previousEventCallBack === 'function') {
      output = previousEventCallBack(e);
      if(output === false) return false;
    }
  }
};

// Now we can rebuild our validation constraint
// Because we do not rely on CSS pseudo-class, we have to 
// explicitly set the valid/invalid class on our email field
addEvent(window, "load", function () {
  // Here, we test if the field is empty (remember, the field is not required)
  // If it is not, we check if its content is a well-formed e-mail address.
  const test = email.value.length === 0 || emailRegExp.test(email.value);

  email.className = test ? "valid" : "invalid";
});

// This defines what happens when the user types in the field
addEvent(email, "input", function () {
  const test = email.value.length === 0 || emailRegExp.test(email.value);
  if (test) {
    email.className = "valid";
    error.innerHTML = "";
    error.className = "error";
  } else {
    email.className = "invalid";
  }
});

// This defines what happens when the user tries to submit the data
addEvent(form, "submit", function () {
  const test = email.value.length === 0 || emailRegExp.test(email.value);

  if (!test) {
    email.className = "invalid";
    error.innerHTML = "I expect an e-mail, darling!";
    error.className = "error active";

    // Some legacy browsers do not support the event.preventDefault() method
    return false;
  } else {
    email.className = "valid";
    error.innerHTML = "";
    error.className = "error";
  }
});

 

结果看起来像这样:

 

如您所见,自行构建验证系统并不难。困难的部分是使其足够通用,以同时使用跨平台和您可能创建的任何形式。

有许多可用于执行表单验证的库,例如Validate.js


 

摘要

如果您要自定义样式和错误消息,则有时需要使用JavaScript进行客户端表单验证,但始终需要您仔细考虑用户。

永远记住要帮助您的用户更正他们提供的数据。为此,请确保:

  • 显示明确的错误消息。
  • 允许输入格式。
  • 指出错误发生的确切位置,特别是在大型表格上。

一旦您检查了正确填写的表格,就可以提交表格。接下来我们将介绍发送表单数据


 

在这里H5的东西基本足够了

 

下面的补充要等到C3 + JS再去了解:

 

自定义表单控件: https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Forms/How_to_build_custom_form_widgets

JavaScript发送表单: https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript

古董浏览器兼容问题: https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Forms/HTML_forms_in_legacy_browsers

表单样式化: https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Forms/Styling_HTML_forms

高级设计CSS:  https://developer.mozilla.org/zh-CN/docs/Learn/HTML/Forms/Advanced_styling_for_HTML_forms

 

posted @ 2020-05-06 12:36  emdzz  阅读(521)  评论(0编辑  收藏  举报