为何ES6中addEventListener仅生效一次?
为什么你的addEventListener只生效一次?
嘿,我懂你碰到的问题——点一次按钮能正常计数,再点就没反应了对吧?咱们来拆解下问题到底出在哪。
先贴出你的代码方便分析:
JavaScript代码:
let input = document.querySelector(".send"); let i = 0; input.addEventListener('click',(e)=>{ e.preventDefault(); i+=1; document.body.innerHTML += i; });
HTML代码:
<input type="submit" class="send">
问题根源:DOM元素被销毁了!
罪魁祸首就是这句 document.body.innerHTML += i。当你用这种方式修改innerHTML时,浏览器会做两件关键的事:
- 把当前
<body>里的所有内容(包括你绑定了事件的那个.send按钮)全部移除并销毁 - 把原来的内容加上新的
i值,重新渲染成一套全新的DOM元素
简单说:你第一次点击后,原来的按钮已经被删掉了,新生成的按钮虽然看起来一模一样,但它是个完全没绑定事件的新元素,所以后续点击自然没反应。
几种靠谱的解决方案
方案1:不要修改整个body的innerHTML,单独更新计数元素
这是最推荐的方式,避免动到按钮所在的DOM结构:
let input = document.querySelector(".send"); let i = 0; // 先创建一个专门用来显示计数的元素 let counter = document.createElement('span'); document.body.appendChild(counter); input.addEventListener('click',(e)=>{ e.preventDefault(); i+=1; // 只更新计数元素的内容,不碰其他DOM counter.textContent = i; });
方案2:用事件委托(Event Delegation)
如果一定要修改innerHTML,可以把事件绑定在不会被销毁的父元素(比如<body>)上,利用事件冒泡来处理:
let i = 0; // 把事件绑定在body上,监听所有点击 document.body.addEventListener('click',(e)=>{ // 判断点击的是不是目标按钮 if(e.target.classList.contains('send')){ e.preventDefault(); i+=1; document.body.innerHTML += i; } });
不管按钮被重新渲染多少次,只要它带.send类,点击事件都会被<body>捕获并处理。
方案3:每次修改后重新绑定事件(不推荐,但可用)
这个方法有点冗余,但也算一种思路——每次更新innerHTML后,重新找到新按钮并绑定事件:
let i = 0; function bindClickEvent(){ let input = document.querySelector(".send"); input.addEventListener('click',(e)=>{ e.preventDefault(); i+=1; document.body.innerHTML += i; // 重新给新生成的按钮绑定事件 bindClickEvent(); }); } // 初始绑定一次 bindClickEvent();
内容的提问来源于stack exchange,提问作者Rso Invisible
相关产品推荐
相关产品推荐

