使用JS实现表格每行按钮组切换的问题排查
问题分析
你遇到的是典型的闭包作用域问题:循环中用var声明的group是函数作用域变量,循环结束后所有点击事件的回调函数都会引用同一个group变量——也就是最后一行的按钮集合,所以不管点哪行的按钮,都会操作最后一行的按钮组。
解决方案
方案1:用let替代var(最简单)
let是块级作用域,每次循环会创建独立的group变量,确保每个回调引用的是当前行的按钮集合:
var toggleGroup = (group, group2, className = "hidden") => { group.classList.toggle(className); group2.classList.toggle(className); } var table = document.querySelector('.hour-section'); // 把var改成let,让group成为块级作用域变量 for (let i = 0, row; row = table.rows[i]; i++) { let group = row.querySelectorAll('.temp-percent'); group.forEach(element => { element.addEventListener("click", () => { toggleGroup(group[0], group[1]) }); }) }
方案2:事件委托(更高效,推荐)
直接给父元素table绑定一次事件,通过事件冒泡判断点击目标,再找到当前行的按钮组,避免循环绑定多个事件:
var toggleGroup = (group, group2, className = "hidden") => { group.classList.toggle(className); group2.classList.toggle(className); } var table = document.querySelector('.hour-section'); table.addEventListener('click', function(e) { // 判断点击的是目标按钮 if (e.target.closest('.temp-percent')) { // 找到当前按钮所在的行 const row = e.target.closest('tr'); const group = row.querySelectorAll('.temp-percent'); toggleGroup(group[0], group[1]); } });
方案3:闭包保存作用域(兼容旧环境)
如果需要兼容不支持let的旧浏览器,可以用立即执行函数(IIFE)把当前行的group封装到独立作用域:
var toggleGroup = (group, group2, className = "hidden") => { group.classList.toggle(className); group2.classList.toggle(className); } var table = document.querySelector('.hour-section'); for (var i = 0, row; row = table.rows[i]; i++) { var group = row.querySelectorAll('.temp-percent'); // 用IIFE保存当前group的引用 (function(currentGroup) { currentGroup.forEach(element => { element.addEventListener("click", () => { toggleGroup(currentGroup[0], currentGroup[1]) }); }) })(group); }
效果验证
修改后,点击任意行的Temp或Chance of Precip按钮,只会切换当前行对应的按钮组的hidden类,不会影响其他行。
内容的提问来源于stack exchange,提问作者Marko
相关产品推荐
相关产品推荐

