循环生成表格TD时绑定Click Listener的问题求助
这是典型的闭包陷阱问题,我来帮你拆解原因和解决办法:
问题根源
你在循环里给每个<td>绑定点击事件,但事件函数里引用的i和j是循环外层的变量。当点击事件真正触发时,循环早就执行完毕了,此时i和j已经是最后一次循环的数值(也就是5和3),所以所有单元格点击后都会显示5.3。
另外还要提一句:你原代码里的<td>标签没有闭合,建议补全为'<td>'+intCell+'</td>',避免DOM结构异常。
解决方案
方案1:用立即执行函数(IIFE)捕获当前循环值
通过IIFE把每次循环的i和j值“固定”下来,让事件函数引用的是当前迭代的变量:
var functionCreate = function(intWidth, intHeight) { var myRow; var intCell; $('#output').append('<table border = "1"></table>'); for(var i = 0; i< intHeight;i++){ $('#output').find('table').append('<tr>'); for(var j = 0; j < intWidth; j ++){ intCell = 'click me'; $('#output').find('tr:last').append('<td>'+intCell+'</td>'); // 用IIFE捕获当前的i和j (function(currentI, currentJ) { $('#output').find('tr:last td:last').on('click', function(){ $(this).text((currentI+1).toString()+'.'+(currentJ+1).toString()); }) })(i, j); } } return $('#output'); };
这里把事件绑定的选择器改成了tr:last td:last,避免每次循环给所有已存在的<td>重复绑定事件。
方案2:使用ES6的let声明循环变量(最简洁)
把循环里的var换成let,利用let的块级作用域特性,每次循环都会创建一个新的变量绑定,事件函数引用的就是当前迭代的数值:
var functionCreate = function(intWidth, intHeight) { var myRow; var intCell; $('#output').append('<table border = "1"></table>'); // 把var改成let for(let i = 0; i< intHeight;i++){ $('#output').find('table').append('<tr>'); // 内层循环也用let for(let j = 0; j < intWidth; j ++){ intCell = 'click me'; $('#output').find('tr:last').append('<td>'+intCell+'</td>'); $('#output').find('tr:last td:last').on('click', function(){ $(this).text((i+1).toString()+'.'+(j+1).toString()); }) } } return $('#output'); };
方案3:事件委托(最推荐,性能最优)
不用给每个<td>单独绑定事件,而是把事件绑定在父元素<table>上,利用事件冒泡机制处理。这样只需要绑定一次事件,还能避免闭包问题:
var functionCreate = function(intWidth, intHeight) { var myRow; var intCell; $('#output').append('<table border = "1"></table>'); // 缓存表格元素,避免重复DOM查询 var $table = $('#output').find('table'); for(var i = 0; i< intHeight;i++){ $table.append('<tr>'); var $currentRow = $table.find('tr:last'); for(var j = 0; j < intWidth; j ++){ intCell = 'click me'; $currentRow.append('<td>'+intCell+'</td>'); } } // 只绑定一次事件到表格上 $table.on('click', 'td', function() { var $td = $(this); // 通过DOM方法获取行号和列号(+1是因为index从0开始) var rowNum = $td.parent().index() + 1; var colNum = $td.index() + 1; $td.text(`${rowNum}.${colNum}`); }); return $('#output'); };
这种方式在表格行数/列数很多时,性能优势会非常明显,而且代码逻辑更清晰。
内容的提问来源于stack exchange,提问作者C. O.
相关产品推荐
相关产品推荐

