JavaScript嵌套for循环绑定点击事件后按钮点击触发两次如何解决
问题原因定位
你遇到的打印两次的问题,大概率是以下两种情况导致的:
- 事件监听器重复绑定:如果这段给
#parent-list绑定点击事件的代码被执行了两次,每次点击都会触发两次回调函数,自然会输出两次Hello world。你可以在回调函数第一行加console.log('回调执行')验证,如果这行也打印两次,就可以确认是绑定重复的问题,解决方法是保证绑定代码只执行一次,或者绑定前先调用removeEventListener移除旧的监听器。 - 匹配到符合条件的元素后没有终止循环:你的嵌套循环只要满足条件就会执行打印,没有跳出逻辑。如果你的DOM结构里存在嵌套的、ID符合
cr-id-x_y格式的元素,或者点击位置同时命中了e.target.nodeName == "BUTTON"和e.target.parentElement.nodeName == "BUTTON"的判断,就可能触发多次打印。另外你的嵌套循环写法性能极差,每次点击都要执行3000次判断,完全没有必要。
修复方案
建议直接抛弃嵌套循环的写法,改用选择器前缀匹配提取目标元素,逻辑更简洁也不会出现重复触发的问题:
document.getElementById("parent-list").addEventListener("click", function (e) { // 匹配最近的ID以cr-id-开头的列表项 const targetCrItem = e.target.closest('[id^="cr-id-"]'); if (!targetCrItem) return; // 匹配最近的按钮元素,自动覆盖按钮本身/按钮内部元素两种场景 const targetBtn = e.target.closest('button'); if (targetBtn) { console.log("Hello world"); // 还可以直接提取索引,不需要循环判断 const [x, y] = targetCrItem.id.replace('cr-id-', '').split('_').map(Number); // 后续业务逻辑可以直接用x、y } });
如果一定要保留你原有的循环写法,只需要在打印后跳出两层循环即可:
document.getElementById("parent-list").addEventListener("click", function (e) { // 给外层循环加标签 outerLoop: for (let x = 0; x < 100; x++) { for (let i = 0; i < 30; i++) { if ( e.target.closest(`#cr-id-${x}_${i}`) && (e.target.nodeName == "BUTTON" || e.target.parentElement.nodeName == "BUTTON") ) { console.log("Hello world"); // 跳出外层循环,终止后续所有判断 break outerLoop; } } } });
内容的提问来源于stack exchange,提问作者mellows
相关产品推荐
相关产品推荐

