Chrome中OnBlur事件重复触发问题求助
嗨,我来帮你搞定这个Chrome里blur事件重复触发的麻烦事儿~
你遇到的情况挺典型的:这段动态生成输入框的代码,在Chrome里会反复触发blur事件,IE表现完全符合预期,Firefox只有创建两个输入元素时才会出问题。你的需求是输入框失焦时弹出提示(实际业务里是检查表格重复项),点击确定后让输入框重新获得焦点,而且还有个有意思的现象——Chrome开始重复触发事件时,切换到其他标签页再切回来,点击确定后这次失焦的问题就自动好了。
原代码示例
HTML部分:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <html> <head> </head> <body> <div></div> <button>generate new element</button> </body> </html>
JS部分:
$(document).ready(function() { $("button").click(function() { $("div").append('<input type="text" name="txtCompanyName" maxlength="100" class="Company" style="margin-bottom:0px;width:170px"/>') }); // With on(): $("div").on("blur", ".Company", function() { alert($(this).text()); $(".Company").focus(); }); });
问题分析
首先有个小细节要修正:输入框的内容应该用val()获取,而不是text()——text()是用来获取元素的文本内容的,输入框的实际内容存在value属性里,所以原代码里的alert($(this).text())得改成alert($(this).val())。
至于Chrome里重复触发blur的核心原因,是Chrome的焦点处理机制在遇到alert弹窗时会出现冲突:当输入框失焦触发blur事件,弹出alert后,浏览器的焦点会被alert抢占;当你点击确定关闭alert后,立即执行$(".Company").focus(),这时候Chrome还没完成焦点状态的重置,导致焦点切换过程中再次触发blur事件,形成循环。而切换标签页再回来正常,是因为切换标签页时浏览器会重置焦点状态,后续的focus操作就能正常执行了。
解决方案
方案一:用setTimeout延迟执行focus
把focus操作放到setTimeout里(延迟0毫秒,本质是把任务放到事件队列末尾,等alert的弹窗处理完成后再执行),避免浏览器焦点冲突:
$(document).ready(function() { $("button").click(function() { $("div").append('<input type="text" name="txtCompanyName" maxlength="100" class="Company" style="margin-bottom:0px;width:170px"/>') }); $("div").on("blur", ".Company", function() { const $currentInput = $(this); alert($currentInput.val()); // 修正为val()获取输入内容 // 延迟执行focus,避开焦点冲突 setTimeout(function() { $currentInput.focus(); }, 0); }); });
方案二:添加标记位阻止重复触发
通过一个布尔变量标记当前是否正在处理blur事件,直接拦截重复触发的事件:
$(document).ready(function() { let isProcessingBlur = false; // 标记位,防止重复处理 $("button").click(function() { $("div").append('<input type="text" name="txtCompanyName" maxlength="100" class="Company" style="margin-bottom:0px;width:170px"/>') }); $("div").on("blur", ".Company", function() { if (isProcessingBlur) return; // 如果正在处理,直接返回 isProcessingBlur = true; const $currentInput = $(this); alert($currentInput.val()); $currentInput.focus(); isProcessingBlur = false; // 处理完成后重置标记 }); });
另外还要注意:原代码里的$(".Company").focus()会让所有带有Company类的输入框中第一个获焦,如果你想让当前失焦的那个输入框重新获焦,一定要用$(this).focus()而不是选择所有元素哦~
内容的提问来源于stack exchange,提问作者Mayank Singh

