原始代码(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("系统错误"); });
});
四个已过时:
  1. jQuery.validator 1.x 已多年不更新,新项目不推荐。
  2. unobtrusiveValidation 是 ASP.NET MVC 5 内置客户端校验,ASP.NET Core 已移除。
  3. $.ajax().success()/.error() 是 jQuery 1.8 / 3.x 的写法,jQuery 4.0 已删除(用 done/fail)。
  4. 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.unobtrusiveHTML5 + 服务端 ModelState
$.ajax({}).success()fetch() / axios
$(selector).on("submit", fn)原生 addEventListener("submit")
jQuery $.extend()Object.assign()
$.validator.messages翻译表 + i18n 库(如 i18next)

使用准则

  1. 新项目不要装 jQuery——它仍然是 90 KB+ 体积,对于表单场景完全是浪费。
  2. 服务端校验永远不能省——HTML5 约束 + JS 库只能"提示",最终以前端提交为准。
  3. i18n 错误信息用 i18next / react-intl 等正式库,不要写 $.extend($.validator.messages, ...)。
  4. 复杂校验(密码强度、依赖字段、异步校验)必须用 Zod / Valibot,HTML5 表达力不够。
  5. 文件上传永远用 FormData,永远不手动设 Content-Type。
参考资料