Event bubbling问题:点击函数未等待含Observable的blur函数完成
解决模态框提交时等待输入框异步校验完成的问题
核心思路
问题本质是blur事件触发的异步校验(接口请求+订阅)还未完成,click提交逻辑就已执行。要解决这个问题,关键是统一管理所有输入框的校验异步任务,让提交操作必须等待所有校验完成后再执行。
可行方案
1. 统一维护校验Promise集合(最可靠)
给每个输入框绑定一个校验Promise,提交时主动触发未校验输入的blur,并等待所有校验Promise完成后再判断是否提交。
示例代码:
// 存储每个输入框的校验Promise,键为输入框ID const validationTasks = new Map(); // 输入框blur校验逻辑(封装为Promise) function validateInput(inputEl) { // 若当前输入框正在校验,直接返回已有的Promise if (validationTasks.has(inputEl.id)) { return validationTasks.get(inputEl.id); } // 封装接口请求为Promise const validatePromise = fetch(`/api/validate/${inputEl.id}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ value: inputEl.value }) }) .then(res => res.json()) .then(result => { // 更新输入框状态(比如添加错误样式) inputEl.classList.toggle('input-error', !result.valid); return result.valid; }) .finally(() => { // 校验完成后移除任务记录 validationTasks.delete(inputEl.id); }); validationTasks.set(inputEl.id, validatePromise); return validatePromise; } // 提交按钮点击处理逻辑 async function handleSubmit(e) { e.preventDefault(); // 先让当前聚焦的输入框触发blur(确保触发校验) document.activeElement?.blur(); // 收集所有输入框的校验任务 const allInputs = document.querySelectorAll('.modal-input'); const allValidationResults = await Promise.all( Array.from(allInputs).map(input => validateInput(input)) ); // 所有校验通过再执行提交 if (allValidationResults.every(isValid => isValid)) { // 执行表单提交逻辑(比如调用提交接口、关闭模态框) console.log('表单合法,执行提交'); } else { // 提示用户存在非法输入 console.log('存在未通过校验的输入'); } }
2. 禁用提交按钮直到校验完成
- 给每个输入框添加「校验中」状态,只要有输入框处于校验中,就禁用提交按钮
- 所有输入框校验完成且全部合法时,再启用按钮
- 提交时仍保留上述Promise校验逻辑做兜底,避免边界情况
3. 微小延迟兜底(不推荐作为主要方案)
利用事件队列特性,给提交逻辑加100ms左右的延迟,让blur的异步校验有机会完成。这种方法仅作为补充,不能完全依赖,因为网络请求耗时不稳定。
function handleSubmit(e) { e.preventDefault(); setTimeout(async () => { const isValid = await validateAllInputs(); if (isValid) { // 执行提交 } }, 100); }
关键注意点
- 不要依赖
blur与click的触发顺序做同步逻辑,异步操作会打破这个顺序 - 校验逻辑要确保幂等:同一个输入框重复触发校验时,复用同一个Promise,避免重复请求接口
- 优先使用表单的
submit事件而非按钮的click事件,兼容性更好
内容的提问来源于stack exchange,提问作者tb517
相关产品推荐
相关产品推荐

