Bootstrap 5学习教程,从入门到精通,Bootstrap 5 表单验证语法知识点及案例代码(34)

发布于:2025-07-07 ⋅ 阅读:(15) ⋅ 点赞:(0)

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>

五、最佳实践

  1. 用户体验:
    • 提供清晰的错误提示
    • 实时验证(如字符计数)可以改善用户体验
    • 错误信息要具体且有帮助
  2. 性能考虑:
    • 避免在大型表单上使用实时验证
    • 复杂的正则表达式可能影响性能
  3. 无障碍访问:
    • 确保错误信息对屏幕阅读器可见
    • 使用适当的 ARIA 属性
  4. 安全性:
    • 客户端验证不能替代服务器端验证
    • 敏感数据(如密码)应在服务器端进行严格验证

通过这个完整的示例,你可以掌握 Bootstrap 5 表单验证的所有核心功能,并根据实际需求进行调整和扩展。


网站公告

今日签到

点亮在社区的每一天
去签到