3 回答
TA贡献1863条经验 获得超2个赞
您需要将事件侦听器的赋值包装在闭包中,例如:
var td;for (var t = 1; t < 8; t++){ td = document.getElementById('td'+t); if (typeof window.addEventListener === 'function'){ (function (_td) { td.addEventListener('click', function(){ console.log(_td); }); })(td); }}
TA贡献1772条经验 获得超6个赞
发生了什么
变量td
是在事件处理程序之外定义的,因此当您单击单元格时,您将记录它设置的最后一个值。
更技术上:每个事件处理函数都是一个闭包 - 一个引用外部作用域变量的函数。
一般的解决方案
这类问题的一般解决方案是从包装函数返回事件处理程序,将要“修复”的变量作为参数传递:
td.addEventListener('click', function(wrapTD) { return function() { console.log(wrapTD); }}(td));
参数现在绑定到调用的包装函数的范围。
更简单的解决方案:使用 this
然而,有一个更简单的选择。在事件处理程序中,this
设置为定义处理程序的元素,因此您可以使用this
而不是td
:
td.addEventListener('click', function() { console.log(this);});
更简单:没有循环!
最后,您可以for
完全摆脱循环并在整个表上设置单个事件处理程序:
var table = document.getElementById('my-table');table.addEventListener('click', function(e) { if (e.target.nodeName.toUpperCase() !== "TD") return; var td = e.target; console.log(td);});
对于较大的表,这是一个更好的解决方案,因为您只用一个替换多个事件处理程序。请注意,如果将文本包装在另一个元素中,则需要对其进行调整以检查目标元素是否为a的后代td
。
TA贡献1891条经验 获得超3个赞
所以这里发生的是你将变量'td'保留在事件监听器函数的范围内。只有1个'td'实例,每次for循环迭代时都会更新。因此,当for循环结束时,td的值现在设置为元素'#td7',并且您的事件处理程序只是记录td的当前值。
在上面的示例中,您只需记录'this':
var td;for (var t=1;t<8;t++){ td = document.getElementById('td'+t); if (typeof window.addEventListener==='function'){ td.addEventListener('click',function(){ console.log(this); }); }}
因为'this'被设置为一个事件被绑定的元素,用于执行事件处理程序。
我猜你在寻找关于在for循环中创建闭包时保持迭代器的更多答案。为此,您需要在for循环之外定义一个函数。
for (var t=1;t<8;t++){ bind_event(t);}function bind_event(t) { var td = document.getElementById('td'+t); if (typeof window.addEventListener==='function'){ td.addEventListener('click',function(){ console.log(td); }); }}
这样,每次运行bind_event时都会创建一个名为'td'的变量实例,并且该实例将保留在事件监听器函数的闭包中。值得注意的是bind_event中的't'也是一个新变量。
添加回答
举报