Bootstrap结合Ajax表单验证 beforeSend逻辑异常排查
问题核心原因
你的代码存在两个致命逻辑错误,导致请求被异常拦截无法正常发送:
- 非空校验判断条件完全写反:当前逻辑是任意一个输入框不为空就终止请求,等同于只有所有输入框全空时才会发送请求,和非空校验的目标完全相反。正确的非空校验逻辑应该是:只要存在任意一个必填字段为空,就拦截请求,所有字段填写完成后才允许请求发送。
- 文件字段校验方式错误:用
value属性判断文件上传字段是否有值是无效的,多文件上传input需要通过files集合的长度判断是否选中了文件,原有判断逻辑就算用户选了文件也会判定为空。
另外你当前在校验失败时调用xhr.abort()会触发ajax的error回调,会弹出“发送失败”的错误提示,和校验失败的场景不匹配,更合理的方式是把校验逻辑前置到ajax调用之前执行,校验不通过直接返回,不发起ajax请求。
修正后可运行代码
$(document).ready(function () { var frm = $('#formulario'); frm.submit(function (e) { e.preventDefault(); $.ajax({ type: frm.attr('method'), url: frm.attr('action'), data: new FormData(this), processData: false, contentType: false, beforeSend : function(xhr, opts) { // 修正判断逻辑:任意一个字段为空就拦截请求 const nombreVal = document.getElementById('nombre').value.trim(); const dniVal = document.getElementById('dni').value.trim(); const correoVal = document.getElementById('correo').value.trim(); const telefonoVal = document.getElementById('telefono').value.trim(); const fechaVal = document.getElementById('fecha').value.trim(); const lugarVal = document.getElementById('lugar').value.trim(); const relacionVal = document.getElementById('relacion').value.trim(); const detalleVal = document.getElementById('detalle').value.trim(); const fileSelected = document.getElementById('archivo[]').files.length > 0; if (!nombreVal || !dniVal || !correoVal || !telefonoVal || !fechaVal || !lugarVal || !relacionVal || !detalleVal || !fileSelected) { frm.addClass('was-validated'); console.log("校验不通过,终止请求"); xhr.abort(); } }, success: function (data) { var div = document.createElement('div'); div.appendChild(document.createTextNode("La denuncia fue enviada con éxito")); div.classList.add('alert', 'alert-success', 'mt-4', 'text-center'); document.querySelector('form').appendChild(div); setTimeout(function() { document.querySelector('.alert').remove(); }, 5000); document.querySelector('form').reset(); frm.removeClass('was-validated'); }, error: function (xhr, status) { // 区分是主动abort还是真的请求错误,避免校验失败弹发送失败提示 if (status === 'abort') return; var div = document.createElement('div'); div.appendChild(document.createTextNode("¡La denuncia no pudo ser enviada, por favor intente nuevamente!")); div.classList.add('alert', 'alert-danger', 'mt-4', 'text-center'); document.querySelector('form').appendChild(div); setTimeout(function() { document.querySelector('.alert').remove(); }, 5000); }, }); }); });
优化建议
如果想让逻辑更清晰,避免abort带来的回调干扰,可以直接把校验逻辑移到发起ajax之前执行,不需要放在beforeSend钩子中:
frm.submit(function (e) { e.preventDefault(); // 先做校验 const nombreVal = document.getElementById('nombre').value.trim(); const dniVal = document.getElementById('dni').value.trim(); const correoVal = document.getElementById('correo').value.trim(); const telefonoVal = document.getElementById('telefono').value.trim(); const fechaVal = document.getElementById('fecha').value.trim(); const lugarVal = document.getElementById('lugar').value.trim(); const relacionVal = document.getElementById('relacion').value.trim(); const detalleVal = document.getElementById('detalle').value.trim(); const fileSelected = document.getElementById('archivo[]').files.length > 0; if (!nombreVal || !dniVal || !correoVal || !telefonoVal || !fechaVal || !lugarVal || !relacionVal || !detalleVal || !fileSelected) { frm.addClass('was-validated'); return false; // 校验不通过直接返回,不发起请求 } // 校验通过再发ajax,不需要再写beforeSend校验逻辑 $.ajax({ type: frm.attr('method'), url: frm.attr('action'), data: new FormData(this), processData: false, contentType: false, success: function (data) { // 原有成功逻辑 }, error: function () { // 原有错误逻辑 } }) })
内容的提问来源于stack exchange,提问作者Aaron Mas
相关产品推荐
相关产品推荐

