动态按钮JS事件监听器不稳定问题:如何实现稳定触发?
问题分析与解决方案
问题出在哪?
你的代码里有个容易忽略的小问题:每次点击「create button」新增按钮时,你都会给所有已存在的.elis按钮重复绑定点击事件。
咱们拆解下具体过程:
- 第一次新增按钮1:给按钮1绑定1次
click监听器,点击它会正常切换背景。 - 第二次新增按钮2:你通过
document.querySelectorAll('.elis')选中了按钮1和按钮2,然后给它们各绑1次监听器。现在按钮1有2次监听器,按钮2有1次。 - 第三次新增按钮3:选中三个按钮各绑1次,此时按钮1有3次监听器,按钮2有2次,按钮3有1次。
这就导致了你的现象:
- 点击按钮1:
toggle执行3次(奇数次),背景会切换,看起来正常; - 点击按钮2:
toggle执行2次(偶数次),等于没切换,所以你觉得它“无法触发”; - 点击按钮3:
toggle执行1次,正常切换。
完全匹配你遇到的情况!
解决方案1:只给新创建的按钮绑定一次监听器
既然每次只新增一个按钮,没必要给所有旧按钮重复绑定,直接给刚创建的btn元素加监听器就行:
//document.ready function function ready(fn) { if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") { fn(); } else { document.addEventListener('DOMContentLoaded', fn); } } ready(function() { document.querySelector('.makeB').addEventListener('click', function() { var btn = document.createElement("button"); var t = document.createTextNode("toggle bg"); btn.appendChild(t); document.body.appendChild(btn); btn.classList.add('elis'); // 只给当前新创建的按钮绑定一次监听器 btn.addEventListener('click', function() { document.body.classList.toggle('bg'); }); }); });
解决方案2:使用事件委托(更优雅的动态元素处理方案)
如果以后要批量处理动态元素,事件委托是更好的选择——只在父元素(比如body)上绑定一次监听器,通过事件冒泡判断点击的目标是不是.elis按钮:
//document.ready function function ready(fn) { if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") { fn(); } else { document.addEventListener('DOMContentLoaded', fn); } } ready(function() { // 给父元素绑定一次事件委托 document.body.addEventListener('click', function(e) { // 判断点击的目标是否是.elis按钮 if (e.target.classList.contains('elis')) { document.body.classList.toggle('bg'); } }); document.querySelector('.makeB').addEventListener('click', function() { var btn = document.createElement("button"); var t = document.createTextNode("toggle bg"); btn.appendChild(t); document.body.appendChild(btn); btn.classList.add('elis'); // 这里不需要再绑定监听器了! }); });
这种方案的优势是:不管后续新增多少个.elis按钮,都不需要再额外绑定监听器,父元素会统一处理所有符合条件的点击事件,性能更优,逻辑也更清晰。
内容的提问来源于stack exchange,提问作者Syden
相关产品推荐
相关产品推荐

