Skip to content

ES6 - 验证

客户端表单验证对于良好的用户体验至关重要。它能立即向用户提供反馈,帮助他们在将数据提交到服务器之前纠正错误。虽然客户端验证提升了用户体验(UX)并能减轻服务器负载,但它不能替代服务器端验证,因为客户端检查可以被绕过。务必始终在服务器端进行数据验证。

现代的客户端验证方法通常将 HTML5 内置的验证属性与 JavaScript 结合使用,以实现更复杂的逻辑和自定义反馈。

  • 内置 HTML5 验证:使用 required、type(例如 email、url、number)、pattern、minlength、maxlength、min、max 等属性。浏览器可以自动检查这些属性并显示默认错误消息。
  • JavaScript 验证:用于自定义验证规则、复杂的跨字段验证,或提供定制的错误消息和用户界面(UI)反馈。

示例:使用 HTML5 验证的 HTML 表单

Section titled “示例:使用 HTML5 验证的 HTML 表单”

这个表单使用 HTML5 属性进行基本验证。浏览器会自动处理一些检查。

<style>
.error-message { color: red; font-size: 0.9em; margin-top: 4px; }
input:invalid { border-color: red; }
</style>
<form id="registrationForm">
<div>
<label for="name">Name:</label>
<input type="text" id="name" name="Name" required minlength="2">
<div class="error-message" id="nameError"></div>
</div>
<div>
<label for="email">Email:</label>
<input type="email" id="email" name="EMail" required>
<div class="error-message" id="emailError"></div>
</div>
<div>
<label for="zip">Zip Code (US):</label>
<input type="text" id="zip" name="Zip" required pattern="\d{5}" title="Enter a 5-digit US zip code.">
<div class="error-message" id="zipError"></div>
</div>
<div>
<label for="country">Country:</label>
<select id="country" name="Country" required>
<option value="">[Choose yours]</option>
<option value="USA">USA</option>
<option value="UK">UK</option>
<option value="INDIA">INDIA</option>
</select>
<div class="error-message" id="countryError"></div>
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>

表单将显示用于输入姓名(Name)、电子邮件(Email)、邮政编码(Zip Code)的字段以及一个用于选择国家(Country)的下拉菜单。如果您尝试提交包含无效数据(例如,必填字段为空,电子邮件或邮政编码格式不正确)的表单,现代浏览器通常会阻止提交并显示默认错误消息或为无效字段添加样式。我们自定义的 CSS input:invalid 将添加红色边框。

用于自定义逻辑和反馈的 JavaScript 验证

Section titled “用于自定义逻辑和反馈的 JavaScript 验证”

我们可以使用 JavaScript 来增强 HTML5 验证或实现完全自定义的验证。这允许更复杂的规则和用户反馈。最佳实践是使用 JavaScript 添加事件监听器,而不是使用 onsubmit 等行内(inline)处理程序。

document.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById('registrationForm');
const nameInput = document.getElementById('name');
const emailInput = document.getElementById('email');
const zipInput = document.getElementById('zip');
const countrySelect = document.getElementById('country');
form.addEventListener('submit', function(event) {
// 阻止默认提交,以便手动处理验证
event.preventDefault();
let isValid = true;
// 清除之前的自定义错误
clearErrorMessages();
// 姓名验证(HTML5 的 'required' 和 'minlength' 处理基本情况)
if (nameInput.value.trim().length < 2) {
displayErrorMessage('nameError', 'Name must be at least 2 characters.');
isValid = false;
}
// 电子邮件验证(HTML5 的 'type=email' 和 'required' 处理基本情况)
// 如果需要,可以进行更具体的模式自定义检查
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailPattern.test(emailInput.value)) {
displayErrorMessage('emailError', 'Please enter a valid email address.');
isValid = false;
}
// 邮政编码验证(HTML5 的 'pattern' 处理格式,'required' 处理存在性)
// 示例:如果需要,可以进行额外的自定义检查
if (zipInput.value.trim() === "00000") {
displayErrorMessage('zipError', 'Zip code cannot be all zeros.');
isValid = false;
}
// 国家验证(HTML5 的 'required' 处理基本情况)
if (countrySelect.value === "") {
displayErrorMessage('countryError', 'Please select your country.');
isValid = false;
}
if (isValid) {
console.log('Form is valid. Submitting data...');
// form.submit(); // 如果需要,可以通过程序提交,或使用 AJAX
alert('Form submitted successfully (simulated)!');
form.reset(); // 可选:提交成功后重置表单
} else {
console.log('Form has errors.');
}
});
function displayErrorMessage(elementId, message) {
const errorElement = document.getElementById(elementId);
if (errorElement) {
errorElement.textContent = message;
}
}
function clearErrorMessages() {
const errorElements = document.querySelectorAll('.error-message');
errorElements.forEach(el => el.textContent = '');
}
// 可选:实时验证(基于输入/改变事件)
nameInput.addEventListener('input', () => {
if (nameInput.validity.valid) {
clearErrorMessages(); // 清除此字段的通用错误
} else if (nameInput.validity.tooShort) {
displayErrorMessage('nameError', `Name needs to be at least ${nameInput.minLength} characters; you entered ${nameInput.value.length}.`);
} else if (nameInput.validity.valueMissing) {
displayErrorMessage('nameError', 'Name is required.');
}
});
// 如有需要,为其他字段添加类似的监听器
});
  • 事件监听器(Event Listener):为表单附加一个 submit 事件监听器。
  • event.preventDefault():阻止默认的表单提交,允许我们的 JavaScript 控制它。
  • 验证逻辑(Validation Logic):检查每个字段。对于某些字段,它依赖于通过 validity API 检查的 HTML5 约束(例如 nameInput.validity.tooShort),而对于其他字段(如电子邮件模式或自定义邮政编码检查),则应用特定的 JS 逻辑。
  • 错误显示(Error Display):使用辅助函数 displayErrorMessage 和 clearErrorMessages 在指定的 div 元素中显示/隐藏消息。
  • 条件提交(Conditional Submission):如果在所有检查后 isValid 保持 true,则可以提交表单(例如,通过程序或 AJAX)。否则,将显示错误。
  • 实时反馈(可选)(Real-time Feedback (Optional)):示例中包含了一个用于 nameInput 的代码片段,展示了如何在使用 input 事件和 ValidityState API(element.validity)时,随着用户输入提供反馈。
  • 用户友好(User-Friendly):提供清晰、简洁且可操作的错误消息。指明哪些字段有错误以及原因。
  • 在多个事件上验证(Validate on Multiple Events):考虑不仅在 submit 事件上验证,还在 blur(字段失去焦点时)或 input(用户输入时)事件上验证,以提供即时反馈。
  • 使用 HTML5 属性(Use HTML5 Attributes):利用内置验证作为第一道防线。它是声明性的,通常不需要 JavaScript。
  • 可访问性(A11y)(Accessibility (A11y)):确保错误消息与各自的表单控件在程序上关联(例如,使用 aria-describedby 或 aria-invalid)。
  • 保持简洁(Keep it Simple):避免过于复杂或侵略性的验证,这可能会让用户感到沮丧。
  • 服务器端回退(Server-Side Fallback):始终在服务器上重新验证。客户端验证是为了用户体验(UX),而不是安全性。