做网页表单时,最常见的需求之一就是控制用户输入:有些字段必须填写,有些字段必须符合特定格式。如果只靠用户自觉,提交上来的数据往往五花八门,空值、乱填的邮箱、纯数字的姓名都会出现。这篇文章就来聊聊怎么给表单设置必填项,以及几种实用的输入验证方法。

用HTML5原生属性设置必填项
HTML5给表单控件提供了不少验证属性,其中最核心的就是required。只需要在<input>、<textarea>或<select>标签上加上这个属性,浏览器就会在提交时自动检查该字段是否有值,为空则阻止提交并弹出提示。这种方式最大的优点是零JavaScript代码,兼容性也好,现代浏览器全部支持。
除了required,还可以搭配pattern属性做格式校验。pattern的值是一个正则表达式,用户输入的内容必须匹配才算通过。另外minlength和maxlength可以限制字符长度,min和max针对数字和日期类型生效。下面这个例子综合运用了这些属性:
<form action="/submit" method="post">
<label>用户名(必填,4到16位字符):
<input type="text" name="username" required minlength="4" maxlength="16">
</label><br>
<label>手机号(必填,11位数字):
<input type="tel" name="phone" required pattern="^1\d{10}$">
</label><br>
<label>邮箱(必填):
<input type="email" name="email" required>
</label><br>
<label>个人简介(选填,最多200字):
<textarea name="bio" maxlength="200"></textarea>
</label><br>
<button type="submit">提交</button>
</form>值得注意的是,type属性本身也带验证逻辑。比如type="email"会检查是否包含合法的邮箱格式,type="url"会检查网址格式,type="number"只允许输入数字。合理利用类型约束,可以少写很多正则。
用JavaScript实现自定义验证和友好提示
原生验证虽然方便,但提示样式由浏览器决定,不同浏览器表现不一致,而且提示文案无法自定义。如果产品对交互体验有要求,就需要用JavaScript接管验证流程。核心思路是监听表单的submit事件,在事件回调里调用checkValidity()或逐个检查字段,验证不通过时调用preventDefault()阻止提交,同时把错误信息渲染到页面上。
失焦验证也是常见的增强手段:用户离开某个输入框时立即校验,填写错误当场就能看到,而不是等到点提交才发现。下面的代码演示了这两者的结合:
<form id="regForm" action="/submit" method="post" novalidate>
<div>
<input type="text" id="username" name="username" placeholder="请输入用户名" required>
<span class="error-msg" id="username-error"></span>
</div>
<div>
<input type="email" id="email" name="email" placeholder="请输入邮箱" required>
<span class="error-msg" id="email-error"></span>
</div>
<button type="submit">注册</button>
</form>
<script>
// 注意form上的novalidate属性,先禁用原生提示,改由自己控制
function validateField(input) {
var msg = '';
if (input.validity.valueMissing) {
msg = '该项为必填,不能为空';
} else if (input.validity.typeMismatch) {
msg = '格式不正确,请检查后重新输入';
}
var errorSpan = document.getElementById(input.id + '-error');
errorSpan.textContent = msg;
input.classList.toggle('invalid', !!msg);
return !msg;
}
// 每个字段失焦时立即验证
document.querySelectorAll('#regForm input').forEach(function (input) {
input.addEventListener('blur', function () {
validateField(input);
});
});
// 提交时统一校验,任一字段不通过就阻止提交
document.getElementById('regForm').addEventListener('submit', function (e) {
var inputs = this.querySelectorAll('input');
var allValid = true;
inputs.forEach(function (input) {
if (!validateField(input)) {
allValid = false;
}
});
if (!allValid) {
e.preventDefault();
}
});
</script>代码里的validity对象是浏览器提供的验证状态对象,包含valueMissing、typeMismatch、patternMismatch等多个布尔属性,分别对应不同的错误类型。通过判断这些属性,可以给出精确的错误提示,比笼统的“输入有误”体验好得多。form标签上的novalidate属性很关键,它禁用了浏览器默认的气泡提示,避免自定义提示和原生提示同时出现。
前端验证不能替代服务端验证
需要特别强调的一点是:无论前端验证做得多完善,都只能算用户体验优化,不能作为数据安全的保障。用户可以禁用JavaScript,也可以直接用工具构造请求绕过表单,把任意数据发给服务器。因此服务端必须再做一遍完整的校验,包括必填检查、格式校验、长度限制、业务规则等,前端验证通过的参数在服务端照样要重新验证一遍。
以常见的后端场景为例,接收表单数据后应该先判空再处理,像下面这段PHP代码展示的流程:
<?php
$username = isset($_POST['username']) ? trim($_POST['username']) : '';
$email = isset($_POST['email']) ? trim($_POST['email']) : '';
$errors = array();
// 必填项检查:前端required挡不住绕过请求,服务端必须再查一次
if ($username === '') {
$errors['username'] = '用户名不能为空';
} elseif (mb_strlen($username) < 4 || mb_strlen($username) > 16) {
$errors['username'] = '用户名长度需在4到16位之间';
}
if ($email === '') {
$errors['email'] = '邮箱不能为空';
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors['email'] = '邮箱格式不正确';
}
if (!empty($errors)) {
// 校验失败,返回错误信息给前端展示
echo json_encode(array('code' => 400, 'errors' => $errors));
exit;
}
// 校验通过,继续后续业务处理
echo json_encode(array('code' => 200, 'msg' => '提交成功'));总结一下做法:前端负责必填提示和即时反馈,让用户填写顺畅;服务端负责最终把关,保证入库数据的合法性和安全性。两端验证规则要保持一致,规则变更时记得同步修改,否则会出现前端放行、后端报错的尴尬情况。掌握这个分层思路,配合上文的原生属性和自定义验证代码,表单验证这个需求基本就能覆盖住了。
表单必填项输入验证required属性修改时间:2026-09-05 00:00:39