循环动态添加div绑定点击事件为何仅打印最后一个元素ID?
问题原因与解决方案
核心原因
你遇到的问题是因为**innerHTML +=的渲染机制导致之前绑定的事件全部丢失**:
每次执行wrapper.innerHTML += ...时,浏览器会把wrapper当前的所有子元素转成HTML字符串,拼接新内容后重新解析成DOM元素替换原内容。这意味着之前添加的div会被重新创建,之前绑定的点击事件会直接失效。只有最后一次循环中给最后一个div绑定的事件会保留,所以点击前面的div没反应,只有点击最后一个会打印它的id。
另外,用document.querySelector每次查询DOM也会额外消耗性能,不是最优的做法。
修复方案
方案1:用createElement创建元素(推荐)
这种方式不会重新渲染已有元素,事件绑定不会丢失:
let arr = ['a', 'b', 'c'] const wrapper = document.querySelector('.wrapper') for (var i = 0; i < arr.length; i++) { const container = document.createElement('div') container.className = 'container' container.id = arr[i] container.onclick = (e) => { console.log(e.target.id) } wrapper.appendChild(container) }
方案2:事件委托(更高效)
不需要给每个div单独绑定事件,利用事件冒泡把事件绑定到父元素上:
let arr = ['a', 'b', 'c'] const wrapper = document.querySelector('.wrapper') // 一次性添加所有元素 arr.forEach(item => { wrapper.innerHTML += `<div class="container" id="${item}"></div>` }) // 父元素统一处理点击事件 wrapper.onclick = (e) => { if (e.target.classList.contains('container')) { console.log(e.target.id) } }
这种方式适合大量元素的场景,减少事件绑定次数,性能更优。
方案3:添加完所有元素后统一绑定事件
如果坚持要用innerHTML +=,可以先把所有元素添加完成,再批量绑定事件:
let arr = ['a', 'b', 'c'] const wrapper = document.querySelector('.wrapper') // 先添加所有div for (var i = 0; i < arr.length; i++) { wrapper.innerHTML += `<div class="container" id="${arr[i]}"></div>` } // 给所有container绑定事件 document.querySelectorAll('.container').forEach(container => { container.onclick = (e) => { console.log(e.target.id) } })
内容的提问来源于stack exchange,提问作者seriously
相关产品推荐
相关产品推荐

