提交表单时滚动动画完成后必填项提示框不显示
问题
我尝试仅使用Bootstrap类和required属性实现必填项提示框显示,但表单使用了submit事件的preventDefault()函数。提交空必填项时,required属性可正常触发滚动动画并定位光标,但“此字段为必填项”的提示框却不出现,仅在空文本框按回车时才显示。怀疑preventDefault()是问题根源,询问是否可手动设置滚动动画和提交时的提示框。
表单情况:
- 约15个带对应
label的for属性和input的name/id的复选框,JS中通过getElementById定义,用checked()验证返回1/0值; - 约10个文件输入框;
- 少数邮箱、姓名等文本输入框;
所有标签已闭合,属性和类验证正确,表单结构无误。
表单代码
<div class="row"> <div class="col-3 d-none d-sm-none d-md-block" style="background-color: #0174bc;"> </div> <div class="col-sm-12 col-md-9 px-3"> <form id="certification_applicant_form" method="POST" class="was-validated"> <hr> <!-- DATOS GENERALES DEL SOLICITANTE --> <h4 class="text-start">Datos generales</h4><br> <div class="row my-2"> <div class="col-sm-12 col-md-6 my-2"> <div class="row"> <div class="col-sm-12 col-md-4 my-2"> <label for="applicant_email"><b>*</b>Correo electrónico:</label> </div> <div class="col-sm-12 col-md-8 my-2"> <input class="form-control" placeholder="ejemplo@correo.com" type="email" id="applicant_email" name="applicant_email" required><br> </div> </div> </div> <div class="col-sm-12 col-md-6 my-2"> <div class="row"> <div class="col-sm-12 col-md-4 my-2"> <label for="applicant_name"><b>*</b>Nombre(s):</label> </div> <div class="col-sm-12 col-md-8 my-2"> <input class="form-control" placeholder="Nombre(s)" type="text" id="applicant_name" name="applicant_name" required><br> </div> </div> </div> <div class="col-sm-12 col-md-6 my-2"> <div class="row"> <div class="col-sm-12 col-md-4 my-2"> <label for="paternal_surname"><b>*</b>Apellido paterno:</label> </div> <div class="col-sm-12 col-md-8 my-2"> <input class="form-control" placeholder="Apellido paterno" type="text" id="paternal_surname" name="paternal_surname" required><br> </div> </div> </div> <div class="col-sm-12 col-md-6 my-2"> <div class="row"> <div class="col-sm-12 col-md-4 my-2"> <label for="maternal_surname"><b>*</b>Apellido materno:</label> </div> <div class="col-sm-12 col-md-8 my-2"> <input class="form-control" placeholder="Apellido materno" type="text" id="maternal_surname" name="maternal_surname" required><br> </div> </div> </div> </div> <hr> <!-- FORMACIÓN ACADÉMICA DEL SOLICITANTE --> <div class="row my-2"> <h4 class="text-start">Formación académica del solicitante</h4><br> <div class="col-sm-12 col-md-6"> <label for="main_degree"><b>*</b>Licenciatura obtenida:</label> <input class="form-control" placeholder="Licenciatura" type="text" id="main_degree" name="main_degree" required><br> </div> <div class="col-12 col-sm-12 col-md-6 "> <label for="main_degree_license"><b>*</b>Cédula profesional:</label> <input maxlength="10" class="form-control" placeholder="Máximo 10 caracteres" type="text" id="main_degree_license" name="main_degree_license" required><br> </div> </div> <div class="row my-2"> <p>Rama(s) de la propiedad intelectual en la que se ha desempeñado los últimos 3 años <br>*Marque todas las que apliquen</p><br> <div class="col-sm-12 col-md-6"> <label for="derechos_autor"> <input class="form-check-input" type="checkbox" name="derechos_autor" id="derechos_autor"> Derechos de autor </label><br> <label for="signos_distintivos"> <input class="form-check-input" type="checkbox" name="signos_distintivos" id="signos_distintivos"> Signos distintivos </label><br> <label for="invenciones"> <input class="form-check-input" type="checkbox" name="invenciones" id="invenciones"> Invenciones </label><br> </div> <div class="col-sm-12 col-md-6"> <label for="secretos_industriales"> <input class="form-check-input" type="checkbox" id="secretos_industriales"> Secretos Industriales </label><br> <label for="litigio"> <input class="form-check-input" type="checkbox" id="litigio"> Litigio de derechos de propiedad intelectual </label><br> <label for="otro"> <input class="form-check-input" type="checkbox" id="otro"> Otro: </label> <input class="form-control" placeholder="Especifique el ramo" type="text" id="otro_text" name="otro_text" disabled> </div> </div> <div class="row my-2"> <h4 class="text-start">Manifiesto de miembro activo en AMPPI</h4><br> <div class="col-9 text-justify"> <label for="verify_active_member"> Solicito verificación por parte de la Gerencia por haber sido miembro del consejo (incluyendo consejo ampliado) </label><br> </div> <div class="col-3 my-auto"> <input class="form-check-input" type="checkbox" id="verify_active_member" name="verify_active_member"></div> </div> <div class="row my-2"> <div class="col-9 text-justify"> <label for="active_member_cv_evidence">La evidencia consta en mi CV en extenso</label><br> </div> <div class="col-3 my-auto"> <input class="form-check-input" type="checkbox" id="active_member_cv_evidence" name="active_member_cv_evidence"> </div> </div> <div class="row my-2"> <div class="col-9"> <label for="active_member_aditional_evidence">Tengo evidencia adicional</label><br> </div> <div class="col-3 my-auto"> <input class="form-check-input" type="checkbox" id="active_member_aditional_evidence" name="active_member_aditional_evidence"> </div> <div id="additional_evidence_div" style="display: none;" class="col-12 my-2 text-center"> <label for="additional_evidence_file">Evidencia adicional:</label> <input class="form-control" type="file" id="additional_evidence_file" name="additional_evidence_file" accept=".pdf, .jpg, .jpeg, .png"><br> </div> </div> <div class="row text-center mx-2 my-4"> <label for="max_files_link">Si tus archivos sobrepasan el máximo permitido en la plataforma, para las preguntas obligatorias por favor sube un archivo que contenga la liga además de incluirla en esta sección.</label> <input class="form-control" id="max_files_link" name="max_files_link"><br> </div> <div class="row text-center my-4"> <label for="terms_and_privacy"> <input class="form-check-input" id="terms_and_privacy" type="checkbox" name="terms_and_privacy"> Acepto Reglas de Certificación AMPPI y Aviso de Privacidad<br> </label> </div> <div class="row text-center mx-2 mt-4"> <div class="col-12"> <button class="btn btn-secondary" type="submit">Enviar solicitud</button> </div> </div> </form> </div>
解决方案
核心原因
浏览器原生的表单验证提示(包括必填提示框)是在表单默认提交流程中触发的,preventDefault()阻止了默认提交,也就跳过了原生验证提示的触发环节,仅保留了滚动定位的行为。
具体实现
1. 手动触发完整原生验证
在submit事件监听函数中,先调用表单的checkValidity()方法触发完整验证(包含提示框),再根据结果处理后续逻辑:
document.getElementById('certification_applicant_form').addEventListener('submit', function(e) { // 触发完整原生验证 const isValid = this.checkValidity(); if (!isValid) { e.preventDefault(); // 手动添加Bootstrap验证状态类,确保样式生效 this.classList.add('was-validated'); } else { // 验证通过,执行自定义提交逻辑 // 若需要自定义提交,保留e.preventDefault();否则可移除 } });
2. 自定义滚动到无效字段(可选)
如果原生滚动不符合需求,可自行获取第一个无效元素并控制滚动:
const firstInvalid = document.querySelector('#certification_applicant_form :invalid'); if (firstInvalid) { // 平滑滚动到元素,添加偏移避免被顶部导航遮挡 firstInvalid.scrollIntoView({ behavior: 'smooth', block: 'center' }); // 聚焦到该元素 firstInvalid.focus(); }
3. 复选框必填补充
若需要复选框(如条款同意)必填,需给其添加required属性,否则原生验证不会检查:
<input class="form-check-input" id="terms_and_privacy" type="checkbox" name="terms_and_privacy" required>
内容的提问来源于stack exchange,提问作者Israel Ornelas
相关产品推荐
相关产品推荐

