Bootstrap 5 表单验证语法知识点及案例代码
Bootstrap 5 提供了强大的客户端表单验证功能,可以轻松地为表单添加验证规则和反馈信息。
一、核心知识点
1. 基本要求
- 需要
novalidate
属性禁用浏览器默认验证 - 使用
.needs-validation
或.was-validated
类控制验证状态 - 验证在表单提交时触发
2. 验证样式类
.is-valid
- 验证通过时应用的样式.is-invalid
- 验证失败时应用的样式.valid-feedback
- 验证成功时显示的提示信息.invalid-feedback
- 验证失败时显示的提示信息
3. HTML5 验证属性
required
- 必填字段pattern
- 正则表达式验证minlength
/maxlength
- 最小/最大长度min
/max
- 最小/最大值(数字)type
- 指定输入类型(email, url等)
4. 自定义验证
- 可以通过 JavaScript 添加自定义验证逻辑
- 使用
setCustomValidity()
方法设置自定义验证消息
二、案例代码1
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bootstrap 5 表单验证示例</title>
<!-- Bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container py-5">
<h1 class="mb-4">Bootstrap 5 表单验证</h1>
<!-- 基本表单验证示例 -->
<form class="row g-3 needs-validation" novalidate>
<h3 class="mt-4">1. 基本表单验证</h3>
<!-- 文本输入验证 -->
<div class="col-md-6">
<label for="firstName" class="form-label">名字</label>
<input type="text" class="form-control" id="firstName" required>
<div class="valid-feedback">
看起来不错!
</div>
<div class="invalid-feedback">
请输入您的名字
</div>
</div>
<!-- 文本输入验证 -->
<div class="col-md-6">
<label for="lastName" class="form-label">姓氏</label>
<input type="text" class="form-control" id="lastName" required>
<div class="valid-feedback">
看起来不错!
</div>
<div class="invalid-feedback">
请输入您的姓氏
</div>
</div>
<!-- 用户名验证(带正则表达式) -->
<div class="col-md-6">
<label for="username" class="form-label">用户名</label>
<div class="input-group has-validation">
<span class="input-group-text">@</span>
<input type="text" class="form-control" id="username"
pattern="[a-zA-Z0-9]{4,}"
title="至少4个字母或数字" required>
<div class="invalid-feedback">
用户名必须至少4个字母或数字
</div>
</div>
</div>
<!-- 邮箱验证 -->
<div class="col-md-6">
<label for="email" class="form-label">邮箱</label>
<input type="email" class="form-control" id="email" required>
<div class="invalid-feedback">
请输入有效的邮箱地址
</div>
</div>
<!-- 密码验证 -->
<div class="col-md-6">
<label for="password" class="form-label">密码</label>
<input type="password" class="form-control" id="password"
minlength="6" required>
<div class="invalid-feedback">
密码必须至少6个字符
</div>
</div>
<!-- 确认密码验证(使用自定义JavaScript验证) -->
<div class="col-md-6">
<label for="confirmPassword" class="form-label">确认密码</label>
<input type="password" class="form-control" id="confirmPassword" required>
<div class="invalid-feedback">
密码不匹配
</div>
</div>
<!-- 数字范围验证 -->
<div class="col-md-6">
<label for="age" class="form-label">年龄</label>
<input type="number" class="form-control" id="age"
min="18" max="100" required>
<div class="invalid-feedback">
年龄必须在18到100之间
</div>
</div>
<!-- 下拉选择验证 -->
<div class="col-md-6">
<label for="country" class="form-label">国家</label>
<select class="form-select" id="country" required>
<option value="">选择国家...</option>
<option value="1">中国</option>
<option value="2">美国</option>
<option value="3">英国</option>
</select>
<div class="invalid-feedback">
请选择一个国家
</div>
</div>
<!-- 单选按钮验证 -->
<div class="col-12">
<label class="form-label">性别</label>
<div class="form-check">
<input class="form-check-input" type="radio" name="gender" id="male" value="male" required>
<label class="form-check-label" for="male">男</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="gender" id="female" value="female">
<label class="form-check-label" for="female">女</label>
</div>
<div class="invalid-feedback" style="display: block;">
请选择性别
</div>
</div>
<!-- 复选框验证 -->
<div class="col-12">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="agree" required>
<label class="form-check-label" for="agree">
我同意条款和条件
</label>
<div class="invalid-feedback">
您必须同意才能继续
</div>
</div>
</div>
<!-- 多选框验证 -->
<div class="col-12">
<label class="form-label">兴趣爱好 (至少选择2项)</label>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="hobbies" id="sports">
<label class="form-check-label" for="sports">运动</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="hobbies" id="music">
<label class="form-check-label" for="music">音乐</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="hobbies" id="reading">
<label class="form-check-label" for="reading">阅读</label>
</div>
<div class="invalid-feedback hobbies-feedback" style="display: block;">
请至少选择2项兴趣爱好
</div>
</div>
<!-- 文件上传验证 -->
<div class="col-12">
<label for="avatar" class="form-label">上传头像 (仅限图片)</label>
<input class="form-control" type="file" id="avatar"
accept="image/*" required>
<div class="invalid-feedback">
请上传头像图片
</div>
</div>
<!-- 文本域验证 -->
<div class="col-12">
<label for="message" class="form-label">留言</label>
<textarea class="form-control" id="message" rows="3"
minlength="10" maxlength="200" required></textarea>
<div class="invalid-feedback">
留言必须在10到200个字符之间
</div>
<small class="form-text text-muted">
已输入 <span id="messageCount">0</span>/200 字符
</small>
</div>
<div class="col-12">
<button class="btn btn-primary" type="submit">提交表单</button>
</div>
</form>
<!-- 工具提示验证示例 -->
<form class="row g-3 mt-5 needs-validation-tooltip" novalidate>
<h3 class="mt-4">2. 工具提示验证</h3>
<div class="col-md-6 position-relative">
<label for="tooltipUsername" class="form-label">用户名</label>
<input type="text" class="form-control" id="tooltipUsername"
placeholder="至少4个字符" required>
</div>
<div class="col-md-6 position-relative">
<label for="tooltipEmail" class="form-label">邮箱</label>
<input type="email" class="form-control" id="tooltipEmail" required>
</div>
<div class="col-12">
<button class="btn btn-primary" type="submit">提交表单</button>
</div>
</form>
<!-- 自定义验证示例 -->
<form class="row g-3 mt-5 needs-custom-validation" novalidate>
<h3 class="mt-4">3. 自定义验证</h3>
<div class="col-md-6">
<label for="customField" class="form-label">自定义验证字段</label>
<input type="text" class="form-control" id="customField"
placeholder="输入'valid'通过验证" required>
<div class="invalid-feedback">
请输入"valid"才能通过验证
</div>
</div>
<div class="col-12">
<button class="btn btn-primary" type="submit">提交表单</button>
</div>
</form>
</div>
<!-- Bootstrap 5 JS Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
// 基本表单验证
(function () {
'use strict'
// 获取需要应用验证的表单
const forms = document.querySelectorAll('.needs-validation')
// 循环处理每个表单
Array.from(forms).forEach(form => {
form.addEventListener('submit', event => {
// 检查密码和确认密码是否匹配(自定义验证)
const password = document.getElementById('password').value;
const confirmPassword = document.getElementById('confirmPassword').value;
if (password !== confirmPassword) {
document.getElementById('confirmPassword').setCustomValidity('密码不匹配');
} else {
document.getElementById('confirmPassword').setCustomValidity('');
}
// 检查兴趣爱好是否至少选择了2项(自定义验证)
const hobbies = document.querySelectorAll('input[name="hobbies"]:checked');
if (hobbies.length < 2) {
document.querySelector('.hobbies-feedback').style.display = 'block';
event.preventDefault();
event.stopPropagation();
} else {
document.querySelector('.hobbies-feedback').style.display = 'none';
}
// 检查表单有效性
if (!form.checkValidity()) {
event.preventDefault()
event.stopPropagation()
}
form.classList.add('was-validated')
}, false)
})
})()
// 工具提示验证
(function () {
'use strict'
// 获取需要应用工具提示验证的表单
const forms = document.querySelectorAll('.needs-validation-tooltip')
// 启用Bootstrap工具提示
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
const tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl)
})
// 循环处理每个表单
Array.from(forms).forEach(form => {
form.addEventListener('submit', event => {
if (!form.checkValidity()) {
event.preventDefault()
event.stopPropagation()
}
// 为每个无效字段添加工具提示
const invalidFields = form.querySelectorAll(':invalid');
invalidFields.forEach(field => {
// 移除现有的工具提示
const existingTooltip = bootstrap.Tooltip.getInstance(field);
if (existingTooltip) {
existingTooltip.dispose();
}
// 创建新的工具提示
const tooltip = new bootstrap.Tooltip(field, {
title: field.validationMessage,
placement: 'right',
trigger: 'manual'
});
tooltip.show();
// 当字段获得焦点时隐藏工具提示
field.addEventListener('focus', () => {
tooltip.hide();
});
});
form.classList.add('was-validated')
}, false)
})
})()
// 自定义验证
(function () {
'use strict'
// 获取需要应用自定义验证的表单
const forms = document.querySelectorAll('.needs-custom-validation')
// 循环处理每个表单
Array.from(forms).forEach(form => {
// 获取自定义验证字段
const customField = form.querySelector('#customField');
// 添加输入事件监听器
customField.addEventListener('input', () => {
if (customField.value === 'valid') {
customField.setCustomValidity('');
customField.classList.remove('is-invalid');
customField.classList.add('is-valid');
} else {
customField.setCustomValidity('请输入"valid"才能通过验证');
customField.classList.remove('is-valid');
customField.classList.add('is-invalid');
}
});
form.addEventListener('submit', event => {
// 检查表单有效性
if (!form.checkValidity()) {
event.preventDefault()
event.stopPropagation()
}
form.classList.add('was-validated')
}, false)
})
})()
// 留言字符计数
document.getElementById('message').addEventListener('input', function() {
const count = this.value.length;
document.getElementById('messageCount').textContent = count;
if (count < 10 || count > 200) {
this.classList.add('is-invalid');
this.classList.remove('is-valid');
} else {
this.classList.add('is-valid');
this.classList.remove('is-invalid');
}
});
</script>
</body>
</html>
三、代码解析
1. 基本表单验证
- 使用
needs-validation
类标识需要验证的表单 - 添加
novalidate
属性禁用浏览器默认验证 - 每个输入字段根据需求添加
required
,pattern
,minlength
等属性 - 提交时通过 JavaScript 检查表单有效性并添加
was-validated
类
2. 工具提示验证
- 使用 Bootstrap 的工具提示组件显示验证错误
- 为无效字段动态创建工具提示
- 当字段获得焦点时隐藏工具提示
3. 自定义验证
- 通过
setCustomValidity()
方法设置自定义验证消息 - 监听输入事件动态检查字段值
- 手动添加/移除验证样式类
4. 特殊验证场景
- 密码匹配验证
- 多选框至少选择N项验证
- 文本域字符计数实时显示
四、案例代码2
以下是一个完整的 Bootstrap 5 表单验证示例,包含用户名、邮箱、密码和确认密码字段,并实现了实时验证和提交验证。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Bootstrap 5 表单验证示例</title>
<!-- 引入 Bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
/* 自定义样式(可选) */
.form-container {
max-width: 500px;
margin: 50px auto;
}
.form-floating > .form-control {
padding-top: 1.5rem;
}
</style>
</head>
<body>
<div class="form-container">
<h2>注册表单</h2>
<form class="row g-3 needs-validation" novalidate>
<!-- 用户名 -->
<div class="col-md-12">
<div class="form-floating">
<input type="text" class="form-control" id="username" placeholder="用户名" required minlength="3" maxlength="20">
<label for="username">用户名</label>
<div class="invalid-feedback">
请输入有效的用户名(3-20 个字符)。
</div>
<div class="valid-feedback">
看起来不错!
</div>
</div>
</div>
<!-- 邮箱 -->
<div class="col-md-12">
<div class="form-floating">
<input type="email" class="form-control" id="email" placeholder="name@example.com" required>
<label for="email">邮箱地址</label>
<div class="invalid-feedback">
请输入有效的邮箱地址。
</div>
<div class="valid-feedback">
邮箱地址有效!
</div>
</div>
</div>
<!-- 密码 -->
<div class="col-md-12">
<div class="form-floating">
<input type="password" class="form-control" id="password" placeholder="密码" required minlength="6">
<label for="password">密码</label>
<div class="invalid-feedback">
密码长度至少为 6 个字符。
</div>
<div class="valid-feedback">
密码设置成功!
</div>
</div>
</div>
<!-- 确认密码 -->
<div class="col-md-12">
<div class="form-floating">
<input type="password" class="form-control" id="confirmPassword" placeholder="确认密码" required minlength="6">
<label for="confirmPassword">确认密码</label>
<div class="invalid-feedback">
确认密码必须与密码一致。
</div>
<div class="valid-feedback">
确认密码匹配!
</div>
</div>
</div>
<!-- 提交按钮 -->
<div class="col-12">
<button class="btn btn-primary" type="submit">注册</button>
</div>
</form>
</div>
<!-- 引入 Bootstrap 5 JS(包含 Popper) -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
// 获取表单元素
const form = document.querySelector('.needs-validation');
// 添加表单提交事件监听
form.addEventListener('submit', function (event) {
// 禁用默认提交行为
if (!form.checkValidity()) {
event.preventDefault();
event.stopPropagation();
}
// 添加 .was-validated 类以触发验证样式
form.classList.add('was-validated');
// 自定义验证逻辑:确认密码
const password = document.getElementById('password');
const confirmPassword = document.getElementById('confirmPassword');
if (password.value !== confirmPassword.value) {
confirmPassword.classList.add('is-invalid');
confirmPassword.classList.remove('is-valid');
event.preventDefault();
event.stopPropagation();
} else {
confirmPassword.classList.add('is-valid');
confirmPassword.classList.remove('is-invalid');
}
});
// 实时验证用户名
const username = document.getElementById('username');
username.addEventListener('input', function () {
if (username.checkValidity()) {
username.classList.add('is-valid');
username.classList.remove('is-invalid');
} else {
username.classList.add('is-invalid');
username.classList.remove('is-valid');
}
});
// 实时验证邮箱
const email = document.getElementById('email');
email.addEventListener('input', function () {
if (email.checkValidity()) {
email.classList.add('is-valid');
email.classList.remove('is-invalid');
} else {
email.classList.add('is-invalid');
email.classList.remove('is-valid');
}
});
// 实时验证密码
const password = document.getElementById('password');
password.addEventListener('input', function () {
if (password.checkValidity()) {
password.classList.add('is-valid');
password.classList.remove('is-invalid');
} else {
password.classList.add('is-invalid');
password.classList.remove('is-valid');
}
});
// 实时验证确认密码
const confirmPassword = document.getElementById('confirmPassword');
confirmPassword.addEventListener('input', function () {
const passwordValue = document.getElementById('password').value;
if (passwordValue === confirmPassword.value) {
confirmPassword.classList.add('is-valid');
confirmPassword.classList.remove('is-invalid');
} else {
confirmPassword.classList.add('is-invalid');
confirmPassword.classList.remove('is-valid');
}
});
</script>
</body>
</html>
五、最佳实践
- 用户体验:
- 提供清晰的错误提示
- 实时验证(如字符计数)可以改善用户体验
- 错误信息要具体且有帮助
- 性能考虑:
- 避免在大型表单上使用实时验证
- 复杂的正则表达式可能影响性能
- 无障碍访问:
- 确保错误信息对屏幕阅读器可见
- 使用适当的 ARIA 属性
- 安全性:
- 客户端验证不能替代服务器端验证
- 敏感数据(如密码)应在服务器端进行严格验证
通过这个完整的示例,你可以掌握 Bootstrap 5 表单验证的所有核心功能,并根据实际需求进行调整和扩展。