如何在jQuery中区分表单提交的成功与失败?
问题根因
当前逻辑的核心bug是:submit 事件触发时,无论后续验证是否通过、实际提交是否会发生,都会立刻清空formHasModifications标记。
由于jQuery事件模型的特性,所有绑定在表单submit事件上的处理器都会按顺序同步执行,哪怕其中某个处理器调用了preventDefault()阻止了实际提交跳转。不管是jQuery Validate还是自定义的验证逻辑,只要它拦截了提交、阻止了页面跳转,你的标记已经被提前清空了,自然就不会在后续导航时弹出未保存提示。
零侵入修改方案(完全适配现有遗留代码结构)
不需要调整页面结构、不需要改动现有验证逻辑,只需要修改原来的submit事件绑定代码即可:
- 原submit处理器代码:
// 原代码 $("form:not(.noprompt)").submit(function (event) { formHasModifications = false; });
- 替换为修改后的代码:
$("form:not(.noprompt)").submit(function (event) { // 把清标记的逻辑延迟到当前事件的所有同步执行逻辑跑完后再执行 setTimeout(function() { // 如果默认提交行为被阻止,说明验证失败、没有实际提交保存,保留修改标记 if (!event.isDefaultPrevented()) { formHasModifications = false; } }, 0); });
方案原理
- 核心逻辑基于jQuery的事件对象
isDefaultPrevented()方法:这个方法可以检测当前事件的默认行为(这里就是表单提交跳转)有没有被代码阻止。 - 用
setTimeout(0)的作用:把清空标记的逻辑推到当前事件循环的同步任务队列末尾,等所有绑定在submit上的处理器(包括所有验证逻辑、其他拦截提交的业务代码)全部执行完毕后,再做判断。 - 完全不用纠结事件绑定顺序:不管验证逻辑是比这个submit处理器先绑定还是后绑定,所有同步的事件处理器都会在setTimeout的回调之前执行完,此时拿到的
isDefaultPrevented()结果是完全准确的:- 验证通过、没有代码阻止提交:正常清空修改标记,页面跳转时不会误弹提示
- 验证失败、有代码调用
preventDefault()阻止跳转:保留修改标记,用户后续导航离开时能正常弹出未保存提示
适配现有代码的注意事项
- 原代码里页面加载完成后,用1ms延迟清空初始化自动修改字段带来的标记的逻辑可以完全保留,不需要改动
- 如果项目里有AJAX提交的表单、但没有加
.noprompt类:这类提交的submit事件通常会被AJAX逻辑调用preventDefault()阻止页面跳转,按照上面的逻辑修改标记不会被清空。这类表单可以在对应AJAX提交的成功回调里手动设置formHasModifications = false即可,不需要改动通用逻辑,完全符合遗留项目不做结构性调整的要求。
内容的提问来源于stack exchange,提问作者Jeff Dege
相关产品推荐
相关产品推荐

