摘要: 在本教程中,您将通过从头开始构建注册表单来学习 JavaScript 表单验证。
什么是表单验证
在将数据提交到服务器之前,您应该在网页浏览器中检查数据,以确保提交的数据格式正确。
为了提供快速反馈,您可以使用 JavaScript 验证数据。这称为客户端验证。
如果您不进行客户端验证,可能会导致用户体验不佳。在这种情况下,您可能会感到明显的延迟,因为表单数据在网页浏览器和服务器之间传输需要时间。
与在网页浏览器中执行的客户端验证不同,服务器端验证在服务器上执行。始终实施服务器端验证至关重要。
原因是客户端验证很容易绕过。恶意用户可以禁用 JavaScript 并将错误数据提交到您的服务器。
在本教程中,您将只关注客户端验证。
客户端验证选项
在客户端验证方面,您有两种选择
- JavaScript 验证:您可以使用 JavaScript 开发验证逻辑。或者,您可以使用库来完成此操作。
- 内置表单验证:您可以使用 HTML5 表单验证功能。这种验证比 JavaScript 验证性能更好。但是,它不像 JavaScript 验证那样可定制。
JavaScript 验证
您将创建一个包含四个输入字段的简单注册表单:用户名、电子邮件、密码和确认密码。
当您单击注册而不填写任何内容或填写不正确的格式的数据时,表单将显示错误消息
您将验证以下内容
- 用户名不能为空,至少 3 个字符,不能超过 25 个字符。
- 电子邮件是强制性的且有效的。
- 密码至少 8 个字符。并且它必须包含 1 个小写字符、1 个大写字符、1 个数字以及至少一个此集合中的特殊字符 (
!@#$%^&*
)。 - 确认密码必须与密码相同。
创建项目结构
首先,创建一个 form-validation
文件夹,用于存储项目的所有源代码文件。
其次,在 form-validation
文件夹内创建 js
和 css
文件夹。
第三,在 css
文件夹中创建 style.css
,在 js
文件夹中创建 app.js
,并在 form-validation
文件夹中直接创建 index.html
。
最终项目结构将如下所示

构建 HTML 表单
首先,打开 index.html
文件并输入以下代码
<!DOCTYPE html>
<html>
<head>
<title>JavaScript Form Validation Demo</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<script src="js/app.js"></script>
</body>
</html>
Code language: HTML, XML (xml)
在此 HTML 文件中,我们将 style.css
文件放在 head
部分,并将 app.js
文件放在 body
部分的 </body>
标签之前。
其次,添加以下 HTML 标记来创建注册表单。最终的 index.html 文件将如下所示
<!DOCTYPE html>
<html>
<head>
<title>JavaScript Form Validation Demo</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="container">
<form id="signup" class="form">
<h1>Sign Up</h1>
<div class="form-field">
<label for="username">Username:</label>
<input type="text" name="username" id="username" autocomplete="off">
<small></small>
</div>
<div class="form-field">
<label for="email">Email:</label>
<input type="text" name="email" id="email" autocomplete="off">
<small></small>
</div>
<div class="form-field">
<label for="password">Password:</label>
<input type="password" name="password" id="password" autocomplete="off">
<small></small>
</div>
<div class="form-field">
<label for="confirm-password">Confirm Password:</label>
<input type="password" name="confirm-password" id="confirm-password" autocomplete="off">
<small></small>
</div>
<div class="form-field">
<input type="submit" value="Sign Up">
</div>
</form>
</div>
<script src="js/app.js"></script>
</body>
</html>
Code language: HTML, XML (xml)
注册表单的显著特点是每个字段都用一个带有 form-field
类别的 div
包装起来。
每个表单字段包含三个元素
- 一个标签
- 一个输入字段
- 一个
<small>
元素
您将使用 <small>
标签向用户显示错误消息。
如果输入字段无效,我们将通过向 form-field
元素添加 error
类来使它的边框颜色变为红色。它将如下所示
<div class="form-field error">
<label for="username">Username:</label>
<input type="text" name="username" id="username" autocomplete="off">
<small></small>
</div>
Code language: JavaScript (javascript)
如果输入字段的值有效,那么我们将通过向 form-field
元素添加 success
类来使它的边框颜色变为绿色,如下所示
<div class="form-field success">
<label for="username">Username:</label>
<input type="text" name="username" id="username" autocomplete="off">
<small></small>
</div>
Code language: JavaScript (javascript)
查看style.css,以了解 .error
和 .success
类的详细信息。
选择表单字段并添加提交事件监听器
在 app.js
文件中,您将首先使用 document.querySelector()
方法选择输入字段和表单
const usernameEl = document.querySelector('#username');
const emailEl = document.querySelector('#email');
const passwordEl = document.querySelector('#password');
const confirmPasswordEl = document.querySelector('#confirm-password');
const form = document.querySelector('#signup');
Code language: JavaScript (javascript)
然后,您通过使用 addEventListener() 方法将 submit
事件监听器附加到表单
form.addEventListener('submit', function (e) {
// prevent the form from submitting
e.preventDefault();
});
Code language: JavaScript (javascript)
在事件监听器中,您需要调用 e.preventDefault()
来阻止表单在单击提交按钮后提交。
开发实用函数
在验证表单之前,您可以开发一些可重复使用的实用函数来检查是否
- 字段是必需的。
- 字段的长度介于最小值和最大值之间。
- 电子邮件格式有效。
- 密码强度高。
以下 isRequired()
函数在输入参数为空时返回 true
const isRequired = value => value === '' ? false : true;
Code language: JavaScript (javascript)
以下 isBetween()
函数在 length
参数不在 min
和 max
参数之间时返回 false
const isBetween = (length, min, max) => length < min || length > max ? false : true;
Code language: JavaScript (javascript)
要检查电子邮件是否有效,您将使用 正则表达式
const isEmailValid = (email) => {
const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
};
Code language: JavaScript (javascript)
要检查密码是否强度高,并且是否与指定模式匹配,您也需要使用正则表达式
const isPasswordSecure = (password) => {
const re = new RegExp("^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*])(?=.{8,})");
return re.test(password);
};
Code language: JavaScript (javascript)
下表说明了用于验证密码的正则表达式的每个部分的含义
密码 RegEx | 含义 |
---|---|
^ | 密码开头 |
(?=.*[a-z]) | 密码必须包含至少一个小写字符 |
(?=.*[A-Z]) | 密码必须包含至少一个大写字符 |
(?=.*[0-9]) | 密码必须包含至少一个数字 |
(?=.*[!@#$%^&*]) | 密码必须包含至少一个特殊字符。 |
(?=.{8,}) | 密码必须至少 8 个字符 |
开发显示错误/成功的函数
以下 showError()
函数突出显示输入字段的边框,并在输入字段无效时显示错误消息
const showError = (input, message) => {
// get the form-field element
const formField = input.parentElement;
// add the error class
formField.classList.remove('success');
formField.classList.add('error');
// show the error message
const error = formField.querySelector('small');
error.textContent = message;
};
Code language: JavaScript (javascript)
工作原理。
首先,获取输入字段的 父元素,即包含 form-field
类的 <div>
元素
const formField = input.parentElement;
Code language: JavaScript (javascript)
其次,从 form-field
元素中删除 success
类并添加 error
类
formField.classList.remove('success');
formField.classList.add('error');
Code language: JavaScript (javascript)
第三,选择 form-field
元素内部的 <small>
元素
const error = formField.querySelector('small');
Code language: JavaScript (javascript)
请注意,您使用 formField.querySelector()
而不是 document.querySelector()
。
最后,将错误消息设置为 <small>
元素的 textContent
属性
error.textContent = message;
显示成功指示器的函数类似于 showError()
函数
const showSuccess = (input) => {
// get the form-field element
const formField = input.parentElement;
// remove the error class
formField.classList.remove('error');
formField.classList.add('success');
// hide the error message
const error = formField.querySelector('small');
error.textContent = '';
}
Code language: JavaScript (javascript)
与 showError()
函数不同,showSuccess()
函数删除 error
类,添加 success
类,并将错误消息设置为空白。
现在,您可以使用上面的实用函数来检查每个字段。
开发输入字段验证函数
您将开发四个函数来验证表单字段的值
1) 验证用户名字段
以下 checkUsername()
函数使用
isRequired()
函数来检查是否提供了用户名。isBetween()
函数来检查用户名的长度是否介于 3 到 25 个字符之间。showError()
和showSuccess()
函数来显示错误和成功指示器。
如果字段通过检查,该函数将返回 true
。
const checkUsername = () => {
let valid = false;
const min = 3,
max = 25;
const username = usernameEl.value.trim();
if (!isRequired(username)) {
showError(usernameEl, 'Username cannot be blank.');
} else if (!isBetween(username.length, min, max)) {
showError(usernameEl, `Username must be between ${min} and ${max} characters.`)
} else {
showSuccess(usernameEl);
valid = true;
}
return valid;
}
Code language: JavaScript (javascript)
2) 验证电子邮件字段
checkEmail()
函数在提供且有效的电子邮件时返回 true
。
它使用 isRequired()
和 isEmailValid()
函数来进行检查。它使用 showError()
和 showSuccess()
函数来在出错和成功的情况下提供反馈。
const checkEmail = () => {
let valid = false;
const email = emailEl.value.trim();
if (!isRequired(email)) {
showError(emailEl, 'Email cannot be blank.');
} else if (!isEmailValid(email)) {
showError(emailEl, 'Email is not valid.')
} else {
showSuccess(emailEl);
valid = true;
}
return valid;
}
Code language: JavaScript (javascript)
3) 验证密码字段
以下 checkPassword()
函数检查密码字段是否已提供,以及是否与所需格式匹配
const checkPassword = () => {
let valid = false;
const password = passwordEl.value.trim();
if (!isRequired(password)) {
showError(passwordEl, 'Password cannot be blank.');
} else if (!isPasswordSecure(password)) {
showError(passwordEl, 'Password must has at least 8 characters that include at least 1 lowercase character, 1 uppercase characters, 1 number, and 1 special character in (!@#$%^&*)');
} else {
showSuccess(passwordEl);
valid = true;
}
return valid;
};
Code language: JavaScript (javascript)
4) 验证确认密码字段
checkConfirmPassword()
函数检查确认密码是否与密码相同。
const checkConfirmPassword = () => {
let valid = false;
// check confirm password
const confirmPassword = confirmPasswordEl.value.trim();
const password = passwordEl.value.trim();
if (!isRequired(confirmPassword)) {
showError(confirmPasswordEl, 'Please enter the password again');
} else if (password !== confirmPassword) {
showError(confirmPasswordEl, 'Confirm password does not match');
} else {
showSuccess(confirmPasswordEl);
valid = true;
}
return valid;
};
Code language: JavaScript (javascript)
修改提交事件处理程序
现在,您可以在提交事件处理程序中使用验证输入字段的函数
form.addEventListener('submit', function (e) {
// prevent the form from submitting
e.preventDefault();
// validate forms
let isUsernameValid = checkUsername(),
isEmailValid = checkEmail(),
isPasswordValid = checkPassword(),
isConfirmPasswordValid = checkConfirmPassword();
let isFormValid = isUsernameValid &&
isEmailValid &&
isPasswordValid &&
isConfirmPasswordValid;
// submit to the server if the form is valid
if (isFormValid) {
}
});
Code language: JavaScript (javascript)
工作原理
- 首先,调用每个单独的函数来验证用户名、电子邮件、密码和确认密码字段。
- 其次,使用
&&
运算符来确定表单是否有效。只有当所有字段都有效时,表单才有效。 - 最后,如果表单有效,则将数据提交到服务器,指定
isFormValid
标志。请注意,在本教程中不涵盖将表单数据提交到服务器。
现在,您可以打开 index.html
文件,输入一些值并单击提交按钮进行测试。
添加即时反馈功能
表单只在您单击 注册 按钮时才会显示错误或成功。
为了提供即时反馈,您可以将事件监听器附加到每个字段的 input
事件,并对其进行验证。
使用 事件委托 更好,这样您就可以将 input
事件监听器附加到表单,并根据当前字段 ID 验证每个字段,例如
form.addEventListener('input', function (e) {
switch (e.target.id) {
case 'username':
checkUsername();
break;
case 'email':
checkEmail();
break;
case 'password':
checkPassword();
break;
case 'confirm-password':
checkConfirmPassword();
break;
}
});
Code language: JavaScript (javascript)
如果您打开 index.html
并输入一些数据,您将看到表单会立即显示反馈,无论是错误还是成功。
此外,您可以通过使用去抖动技术来提高表单的性能。
从技术上讲,您将等待用户暂停键入一小段时间或停止键入,然后再验证输入。
以下是 debounce()
函数的示例
const debounce = (fn, delay = 500) => {
let timeoutId;
return (...args) => {
// cancel the previous timer
if (timeoutId) {
clearTimeout(timeoutId);
}
// setup a new timer
timeoutId = setTimeout(() => {
fn.apply(null, args)
}, delay);
};
};
Code language: JavaScript (javascript)
现在,您可以将 input
事件处理程序传递给 debounce()
函数来对其进行去抖动
form.addEventListener('input', debounce(function (e) {
switch (e.target.id) {
case 'username':
checkUsername();
break;
case 'email':
checkEmail();
break;
case 'password':
checkPassword();
break;
case 'confirm-password':
checkConfirmPassword();
break;
}
}));
Code language: JavaScript (javascript)
如果您在表单字段中输入数据以触发 input
事件,您将看到错误或成功消息将略有延迟。
以下显示了完整的 app.js
文件
const usernameEl = document.querySelector('#username');
const emailEl = document.querySelector('#email');
const passwordEl = document.querySelector('#password');
const confirmPasswordEl = document.querySelector('#confirm-password');
const form = document.querySelector('#signup');
const checkUsername = () => {
let valid = false;
const min = 3,
max = 25;
const username = usernameEl.value.trim();
if (!isRequired(username)) {
showError(usernameEl, 'Username cannot be blank.');
} else if (!isBetween(username.length, min, max)) {
showError(usernameEl, `Username must be between ${min} and ${max} characters.`)
} else {
showSuccess(usernameEl);
valid = true;
}
return valid;
};
const checkEmail = () => {
let valid = false;
const email = emailEl.value.trim();
if (!isRequired(email)) {
showError(emailEl, 'Email cannot be blank.');
} else if (!isEmailValid(email)) {
showError(emailEl, 'Email is not valid.')
} else {
showSuccess(emailEl);
valid = true;
}
return valid;
};
const checkPassword = () => {
let valid = false;
const password = passwordEl.value.trim();
if (!isRequired(password)) {
showError(passwordEl, 'Password cannot be blank.');
} else if (!isPasswordSecure(password)) {
showError(passwordEl, 'Password must has at least 8 characters that include at least 1 lowercase character, 1 uppercase characters, 1 number, and 1 special character in (!@#$%^&*)');
} else {
showSuccess(passwordEl);
valid = true;
}
return valid;
};
const checkConfirmPassword = () => {
let valid = false;
// check confirm password
const confirmPassword = confirmPasswordEl.value.trim();
const password = passwordEl.value.trim();
if (!isRequired(confirmPassword)) {
showError(confirmPasswordEl, 'Please enter the password again');
} else if (password !== confirmPassword) {
showError(confirmPasswordEl, 'The password does not match');
} else {
showSuccess(confirmPasswordEl);
valid = true;
}
return valid;
};
const isEmailValid = (email) => {
const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
};
const isPasswordSecure = (password) => {
const re = new RegExp("^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*])(?=.{8,})");
return re.test(password);
};
const isRequired = value => value === '' ? false : true;
const isBetween = (length, min, max) => length < min || length > max ? false : true;
const showError = (input, message) => {
// get the form-field element
const formField = input.parentElement;
// add the error class
formField.classList.remove('success');
formField.classList.add('error');
// show the error message
const error = formField.querySelector('small');
error.textContent = message;
};
const showSuccess = (input) => {
// get the form-field element
const formField = input.parentElement;
// remove the error class
formField.classList.remove('error');
formField.classList.add('success');
// hide the error message
const error = formField.querySelector('small');
error.textContent = '';
}
form.addEventListener('submit', function (e) {
// prevent the form from submitting
e.preventDefault();
// validate fields
let isUsernameValid = checkUsername(),
isEmailValid = checkEmail(),
isPasswordValid = checkPassword(),
isConfirmPasswordValid = checkConfirmPassword();
let isFormValid = isUsernameValid &&
isEmailValid &&
isPasswordValid &&
isConfirmPasswordValid;
// submit to the server if the form is valid
if (isFormValid) {
}
});
const debounce = (fn, delay = 500) => {
let timeoutId;
return (...args) => {
// cancel the previous timer
if (timeoutId) {
clearTimeout(timeoutId);
}
// setup a new timer
timeoutId = setTimeout(() => {
fn.apply(null, args)
}, delay);
};
};
form.addEventListener('input', debounce(function (e) {
switch (e.target.id) {
case 'username':
checkUsername();
break;
case 'email':
checkEmail();
break;
case 'password':
checkPassword();
break;
case 'confirm-password':
checkConfirmPassword();
break;
}
}));
Code language: JavaScript (javascript)
以及最终表单。
总结
- 什么是客户端验证以及客户端验证与服务器端验证之间的区别。
- 如何组合表单,并将 JavaScript 和 CSS 结合起来验证输入字段。
- 如何使用 正则表达式 检查字段值是否格式正确。
- 如何使用 事件委托 技术。
- 如何使用 去抖动技术 来提高表单验证的性能。