为何jQuery的rows.on("blur", handler)会触发handler无限循环调用?
jQuery blur事件无限重复触发的问题解决
问题描述
使用jQuery 3.6.1实现表单动态添加行功能,核心逻辑是:输入框失焦时检查是否存在三个输入框全为空的行,若不存在则添加新行。但实际运行时,聚焦name以compdiv开头的输入框后失焦,alert弹窗弹出,关闭后会无限重复触发,代码中无其他调用OSH.doDivisions()的逻辑。
初始核心代码:
OSH.setDivisions = function() { let rows = $("input[name^='compdiv']"); rows.on("blur", OSH.doDivisions) } OSH.doDivisions = function() { alert("In doDivisions()"); if (OSH.emptyDivisions() == 0) { OSH.addDivision(); } }
页面初始表格结构:
<tr> <td><input id="compdiv_name[]" name="compdiv_name[]" type="text" style="width:320px"/></td> <td><input id="compdiv_adult[]" name="compdiv_adult[]" type="text" style="width:60px"/></td> <td><input id="compdiv_jr[]" name="compdiv_jr[]" type="text" style="width:60px"/></td> </tr>
后续补充的相关函数及初始化代码:
OSH.emptyDivisions = function() { let numempty = 0; let values = []; let rows = $("input[name^='compdiv']"); for (let i = 0; i < rows.length; ++i) { if (rows[i].type != "text") { continue; } if (rows[i].name == "compdiv_name[]") { values[i] = rows[i].value; if (rows[i + 1].name == "compdiv_adult[]") { values[i] += rows[i + 1].value; if (rows[i + 2].name == "compdiv_jr[]") { values[i] += rows[i + 2].value; if (values[i] == "") { ++numempty; i += 2; } } } } } return numempty; } OSH.addDivision = function() { let data = '\ <tr>\ <td><input id="compdiv_name[]" name="compdiv_name[]" type="text" style="width:320px"/></td>\ <td><input id="compdiv_adult[]" name="compdiv_adult[]" type="text" style="width:60px"/></td>\ <td><input id="compdiv_jr[]" name="compdiv_jr[]" type="text" style="width:60px"/></td>\ </tr>\ '; $("#lastDivision").before(data); } $(document).ready(OSH.setDivisions());
问题原因
- 事件绑定方式错误:
$(document).ready(OSH.setDivisions())直接执行了函数而非传递引用,后续若误触发setDivisions会导致重复绑定,一次失焦触发多次回调。 - 未使用事件委托:直接给初始输入框绑定
blur事件,新添加的输入框无法继承事件,且重复执行绑定逻辑会给已有元素叠加事件。 - alert干扰焦点状态:alert弹窗弹出时会强制输入框失焦,关闭后焦点异常跳转,可能触发额外的
blur事件。 - 空行统计逻辑易出错:按输入框遍历的循环逻辑存在索引越界风险,可能导致空行统计错误,触发不必要的新行添加,间接引发事件异常。
解决方案
1. 修正DOM就绪事件的写法
传递函数引用给ready,确保仅在DOM就绪时执行一次绑定:
$(document).ready(OSH.setDivisions);
2. 使用事件委托绑定事件
将事件委托给表格父元素,新添加的输入框自动继承事件,避免重复绑定:
OSH.setDivisions = function() { // 替换为实际表格的选择器,比如表格id或tbody $("table").on("blur", "input[name^='compdiv']", OSH.doDivisions); }
3. 优化空行统计逻辑
按行遍历统计,逻辑更清晰,避免索引错误:
OSH.emptyDivisions = function() { let numempty = 0; // 遍历包含目标输入框的每一行 $("tr:has(input[name^='compdiv'])").each(function() { const nameVal = $(this).find("input[name='compdiv_name[]']").val().trim(); const adultVal = $(this).find("input[name='compdiv_adult[]']").val().trim(); const jrVal = $(this).find("input[name='compdiv_jr[]']").val().trim(); // 三个输入框均为空时计数+1 if (!nameVal && !adultVal && !jrVal) { numempty++; } }); return numempty; }
4. 替换alert为控制台日志调试
避免alert干扰焦点状态,改用console.log调试:
OSH.doDivisions = function() { console.log("In doDivisions()"); if (OSH.emptyDivisions() == 0) { OSH.addDivision(); } }
内容的提问来源于stack exchange,提问作者sootsnoot
相关产品推荐
相关产品推荐

