原始代码(jQuery 1.x / ASP.NET MVC 5 时代)
1. 验证单个字段
var $jQval = $("#form1").validate();
// 验证姓名
if (!$jQval.element($("#Name"))) {
return false;
}
// 验证手机
if (!$jQval.element($("#Mobile"))) {
return false;
}
2. 修改默认配置
// 不建议写在 dom 加载完成后的事件中,可能会不起作用
jQuery.validator.setDefaults({
ignore: ""
});
$.extend($.validator.messages, {
required: '该项为必填项',
maxlength: $.validator.format("最大长度不能大于{0}个字符"),
minlength: $.validator.format("最小长度不能小于{0}个字符"),
rangelength: $.validator.format("字符长度必须在 {0} 和 {1} 之间"),
range: $.validator.format("数值必须在 {0} 和 {1} 之间"),
max: $.validator.format("数值不能大于 {0}"),
min: $.validator.format("数值不能小于 {0}")
});
3. ASP.NET MVC 集成 + ajax 文件上传
var data_validation = "unobtrusiveValidation";
function validate(form) {
var validationInfo = $(form).data(data_validation);
return !validationInfo || !validationInfo.validate || validationInfo.validate();
}
function onSuccess(data) { /* ... */ }
$(document).on("submit", "form[data-ajax=true]", function (evt) {
evt.preventDefault();
if (!validate(this)) {
return;
}
var formData = new FormData(this);
$.ajax({
url: this.action,
type: this.method,
data: formData,
cache: false,
processData: false,
contentType: false
}).success(function (data) { onSuccess(data); })
.error(function () { alert("系统错误"); });
});
四个已过时:
jQuery.validator1.x 已多年不更新,新项目不推荐。unobtrusiveValidation是 ASP.NET MVC 5 内置客户端校验,ASP.NET Core 已移除。$.ajax().success()/.error()是 jQuery 1.8 / 3.x 的写法,jQuery 4.0 已删除(用done/fail)。FormData+contentType: false仍是文件上传标准写法,这部分保留。
HTML5 原生约束(首选)
现代浏览器原生支持的约束属性已覆盖大部分常见校验:
<form novalidate>
<label for="email">邮箱</label>
<input type="email" id="email" name="email"
required
minlength="3"
maxlength="64"
pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}"
autocomplete="email" />
<label for="age">年龄</label>
<input type="number" id="age" name="age"
min="18" max="120" step="1" required />
<label for="password">密码</label>
<input type="password" id="password" name="password"
minlength="8" maxlength="128"
pattern="(?=.*\d)(?=.*[A-Z]).{8,}"
title="至少 8 位,含数字与大写字母" required />
<label for="agree">同意条款</label>
<input type="checkbox" id="agree" name="agree" required />
<button type="submit">提交</button>
</form>
浏览器原生提示样式可用 :invalid + :valid 选择器定制:
input:invalid:not(:placeholder-shown) { border-color: #dc3545; }
input:valid:not(:placeholder-shown) { border-color: #28a745; }
现代库替代
方案 1:Zod(TypeScript-first,无依赖)
import { z } from 'zod';
const UserSchema = z.object({
email: z.string().email(),
age: z.number().min(18).max(120),
password: z.string().min(8).max(128)
.regex(/[A-Z]/, "至少含一个大写字母"),
agree: z.literal(true)
});
function handleSubmit(form: HTMLFormElement) {
const formData = new FormData(form);
const parsed = UserSchema.safeParse(Object.fromEntries(formData));
if (!parsed.success) {
for (const issue of parsed.error.issues) {
const field = form.querySelector(`[name="${issue.path[0]}"]`);
field?.setAttribute("aria-invalid", "true");
// 显示 issue.message
}
return;
}
// parsed.data 已通过校验
}
优点:纯 TypeScript、类型安全、错误信息结构化。
方案 2:Valibot(Zod 替代,零依赖 + 极小)
import * as v from 'valibot';
const UserSchema = v.object({
email: v.pipe(v.string(), v.email()),
age: v.pipe(v.number(), v.minValue(18), v.maxValue(120)),
password: v.pipe(v.string(), v.minLength(8), v.maxLength(128)),
agree: v.literal(true)
});
优点:bundle 体积小 95%(Zod 14 KB → Valibot 0.7 KB),函数式 API,可 tree-shake。
方案 3:React Hook Form(React 项目)
import { useForm } from "react-hook-form";
function Form() {
const { register, handleSubmit, formState: { errors } } = useForm();
const onSubmit = data => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("email", { required: "必填", pattern: /^\S+@\S+$/ })} />
{errors.email && <span>{errors.email.message}</span>}
<button type="submit">提交</button>
</form>
);
}
优点:React 生态标杆;性能优化好(按需重渲染);TypeScript 支持完善。
文件上传部分:保留 FormData 写法
无论用 jQuery 还是现代 fetch,文件上传部分都长这样:
// 现代 fetch 版
async function uploadFile(form) {
const formData = new FormData(form);
const response = await fetch(form.action, {
method: form.method,
body: formData,
// 不要设置 Content-Type!让浏览器自动加 boundary
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return await response.json();
}
// 带进度
async function uploadFileWithProgress(form, progressBar) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", e => {
if (e.lengthComputable) {
progressBar.value = e.loaded / e.total;
}
});
xhr.addEventListener("load", () => {
if (xhr.status === 200) resolve(JSON.parse(xhr.responseText));
else reject(new Error(xhr.statusText));
});
xhr.open(form.method, form.action);
xhr.send(new FormData(form));
});
}
对照表
| 老方案 | 现代替代 |
|---|---|
jQuery 1.x + $.validate() | HTML5 + Zod / Valibot |
| jquery.validate.unobtrusive | HTML5 + 服务端 ModelState |
$.ajax({}).success() | fetch() / axios |
$(selector).on("submit", fn) | 原生 addEventListener("submit") |
jQuery $.extend() | Object.assign() |
$.validator.messages | 翻译表 + i18n 库(如 i18next) |
使用准则
- 新项目不要装 jQuery——它仍然是 90 KB+ 体积,对于表单场景完全是浪费。
- 服务端校验永远不能省——HTML5 约束 + JS 库只能"提示",最终以前端提交为准。
- i18n 错误信息用 i18next / react-intl 等正式库,不要写
$.extend($.validator.messages, ...)。 - 复杂校验(密码强度、依赖字段、异步校验)必须用 Zod / Valibot,HTML5 表达力不够。
- 文件上传永远用
FormData,永远不手动设Content-Type。