表单验证

确保用户输入数据的准确性和完整性

核心概念

什么是表单验证?

表单验证是在用户提交表单之前,检查输入数据是否符合预期格式的过程。它可以防止无效数据被提交,提高用户体验。

// 验证函数示例 function validateEmail(email) { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); } function validatePassword(password) { return password.length >= 8 && /[A-Z]/.test(password) && /[a-z]/.test(password) && /[0-9]/.test(password); }

验证类型

  • 必填验证:确保字段不为空
  • 格式验证:邮箱、手机号等格式检查
  • 长度验证:字符数量限制
  • 数值验证:数字范围检查
  • 一致性验证:密码确认等

实时验证演示

用户注册表单

用户名格式不正确
用户名可用
请输入有效的邮箱地址
邮箱格式正确
密码强度不足
密码强度良好
密码强度
两次输入的密码不一致
密码一致
请输入正确的手机号
手机号格式正确

验证规则详解

正则表达式验证

// 邮箱验证 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; // 手机号验证(中国) const phoneRegex = /^1[3-9]\d{9}$/; // 用户名验证 const usernameRegex = /^[a-zA-Z0-9_]{3,20}$/; // 密码强度验证 const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$/; // 身份证号验证 const idCardRegex = /^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[0-9Xx]$/;

HTML5原生验证演示

使用说明:

  • 尝试提交空表单,查看HTML5原生提示
  • 在邮箱字段输入非邮箱格式
  • 在年龄字段输入超出范围的数字
  • 在邮政编码字段输入非6位数字
  • 在自定义错误消息字段输入"HTML5"以外的内容

高级验证技巧

异步验证

// 检查用户名是否已存在 async function checkUsernameAvailability(username) { try { const response = await fetch(`/api/check-username?username=${username}`); const data = await response.json(); return data.available; } catch (error) { console.error('检查用户名时出错:', error); return false; } } // 防抖函数 function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } // 使用防抖的验证 const debouncedCheck = debounce(async (username) => { const isAvailable = await checkUsernameAvailability(username); updateUsernameStatus(isAvailable); }, 500);

实时验证演示

输入用户名检查是否可用...

案例:小美的在线订单系统

业务需求

  • • 商品信息验证(库存、价格)
  • • 收货地址验证(格式、完整性)
  • • 支付信息验证(卡号、有效期)
  • • 优惠券验证(有效性、使用条件)
  • • 实时库存检查
  • • 表单提交前的完整性检查

实现架构

class OrderValidator { constructor() { this.validators = { product: new ProductValidator(), address: new AddressValidator(), payment: new PaymentValidator(), coupon: new CouponValidator() }; } async validateOrder(orderData) { const results = {}; // 并行验证各个部分 const validations = [ this.validators.product.validate(orderData.items), this.validators.address.validate(orderData.address), this.validators.payment.validate(orderData.payment), this.validators.coupon.validate(orderData.coupon) ]; try { const [product, address, payment, coupon] = await Promise.all(validations); results.product = product; results.address = address; results.payment = payment; results.coupon = coupon; return { isValid: Object.values(results).every(r => r.isValid), errors: Object.values(results).flatMap(r => r.errors || []), warnings: Object.values(results).flatMap(r => r.warnings || []) }; } catch (error) { return { isValid: false, errors: ['验证过程中发生错误'], warnings: [] }; } } } // 具体验证器 class ProductValidator { async validate(items) { const errors = []; const warnings = []; for (const item of items) { // 检查库存 const stock = await this.checkStock(item.id, item.quantity); if (stock < item.quantity) { errors.push(`${item.name} 库存不足`); } // 检查价格变动 const currentPrice = await this.getCurrentPrice(item.id); if (currentPrice !== item.price) { warnings.push(`${item.name} 价格已更新`); } } return { isValid: errors.length === 0, errors, warnings }; } }

实际演示:订单验证系统

订单信息

数量超出范围
优惠码无效
优惠码有效
请输入完整地址
请输入正确的手机号

练习题(8个实战练习)

练习1:身份证验证器

实现一个身份证号码验证器,包括格式检查和校验位计算。

class IDCardValidator { static validate(id) { // 格式检查 if (!/^\d{17}[\dXx]$/.test(id)) { return { valid: false, message: '身份证号码格式错误' }; } // 校验位计算 const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]; const checkDigits = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']; let sum = 0; for (let i = 0; i < 17; i++) { sum += parseInt(id[i]) * weights[i]; } const checkDigit = checkDigits[sum % 11]; const actualCheckDigit = id[17].toUpperCase(); if (checkDigit !== actualCheckDigit) { return { valid: false, message: '身份证号码校验位错误' }; } return { valid: true, message: '身份证号码有效' }; } static getInfo(id) { if (!this.validate(id).valid) return null; const birth = id.substring(6, 14); const year = birth.substring(0, 4); const month = birth.substring(4, 6); const day = birth.substring(6, 8); const gender = parseInt(id.substring(16, 17)) % 2 === 0 ? '女' : '男'; return { birth: `${year}-${month}-${day}`, gender: gender, age: new Date().getFullYear() - parseInt(year) }; } }

练习2:信用卡验证器

实现一个信用卡号验证器,支持Luhn算法验证。

class CreditCardValidator { static validate(cardNumber) { // 移除空格和连字符 const cleanNumber = cardNumber.replace(/[\s-]/g, ''); // 检查是否为纯数字 if (!/^\d+$/.test(cleanNumber)) { return { valid: false, type: null, message: '卡号只能包含数字' }; } // 检查长度 if (cleanNumber.length < 13 || cleanNumber.length > 19) { return { valid: false, type: null, message: '卡号长度不正确' }; } // Luhn算法验证 if (!this.luhnCheck(cleanNumber)) { return { valid: false, type: null, message: '卡号无效' }; } // 检测卡类型 const cardType = this.detectCardType(cleanNumber); return { valid: true, type: cardType, message: `${cardType}卡有效` }; } static luhnCheck(cardNumber) { let sum = 0; let isEven = false; for (let i = cardNumber.length - 1; i >= 0; i--) { let digit = parseInt(cardNumber[i]); if (isEven) { digit *= 2; if (digit > 9) { digit -= 9; } } sum += digit; isEven = !isEven; } return sum % 10 === 0; } static detectCardType(cardNumber) { const patterns = { 'Visa': /^4/, 'MasterCard': /^5[1-5]/, 'American Express': /^3[47]/, 'Discover': /^6(?:011|5)/ }; for (const [type, pattern] of Object.entries(patterns)) { if (pattern.test(cardNumber)) { return type; } } return 'Unknown'; } }

练习3-5:基础验证

  • • 邮箱格式验证器
  • • 密码强度检测器
  • • 表单完整性检查

练习6-8:高级验证

  • • 实时异步验证
  • • 多级验证系统
  • • 自定义验证规则