如何在JavaScript动态生成的表格中获取td的innerHTML
解决动态生成表格点击单元格无法获取对应文本的问题
这个问题是典型的闭包作用域陷阱,我来帮你拆解原因和解决办法:
为什么原来的代码会出错?
你在循环里给每个td绑定onclick事件时,事件函数并没有立刻执行——它要等到你点击单元格才会触发。而循环结束后,变量td已经指向了最后一次循环创建的那个单元格,所以不管你点哪个单元格,check函数里的td都会指向最后一个单元格的内容。
三种可行的解决方案
方案1:用立即执行函数(IIFE)创建独立作用域
把当前循环的td作为参数传入立即执行函数,让每个事件函数都能捕获到当前的td引用:
var myTableDiv = document.getElementById("results") var table = document.createElement('TABLE') var tableBody = document.createElement('TBODY') table.border = '1' table.appendChild(tableBody); //TABLE ROWS for (i = 0; i < this.memo.length; i++) { var tr = document.createElement('TR'); for (j = 0; j < this.memo[i].length; j++) { var td = document.createElement('TD'); // 用IIFE保存当前td的引用 td.onclick = (function(currentTd) { return function() { check(currentTd); }; })(td); td.appendChild(document.createTextNode(this.memo[i][j])); tr.appendChild(td) } tableBody.appendChild(tr); } myTableDiv.appendChild(table); // 修改check函数,接收当前元素作为参数 function check(element) { var a = element.innerHTML; console.log(a); }
方案2:用ES6的let声明变量(最简单)
let会创建块级作用域,每次循环都会生成一个新的td变量,这样每个事件函数绑定的都是当前循环的td:
var myTableDiv = document.getElementById("results") var table = document.createElement('TABLE') var tableBody = document.createElement('TBODY') table.border = '1' table.appendChild(tableBody); // 外层循环的i也可以用let,避免其他潜在问题 for (let i = 0; i < this.memo.length; i++) { var tr = document.createElement('TR'); // 内层循环用let声明j,确保每次循环的作用域独立 for (let j = 0; j < this.memo[i].length; j++) { let td = document.createElement('TD'); // 用let声明td td.onclick = function () { check(td); } td.appendChild(document.createTextNode(this.memo[i][j])); tr.appendChild(td) } tableBody.appendChild(tr); } myTableDiv.appendChild(table); function check(element) { var a = element.innerHTML; console.log(a); }
方案3:利用元素的自定义属性(最直观)
把要获取的文本直接存在td的自定义data-*属性里,点击时通过this(指向被点击的单元格)获取:
var myTableDiv = document.getElementById("results") var table = document.createElement('TABLE') var tableBody = document.createElement('TBODY') table.border = '1' table.appendChild(tableBody); for (i = 0; i < this.memo.length; i++) { var tr = document.createElement('TR'); for (j = 0; j < this.memo[i].length; j++) { var td = document.createElement('TD'); // 把单词存在自定义data属性里 td.dataset.word = this.memo[i][j]; td.onclick = function () { // this指向被点击的td,直接取属性值 console.log(this.dataset.word); } td.appendChild(document.createTextNode(this.memo[i][j])); tr.appendChild(td) } tableBody.appendChild(tr); } myTableDiv.appendChild(table);
这种方法不需要单独的check函数,逻辑更直接。
总结
推荐用方案2(let)或者方案3(自定义属性),代码更简洁易懂。核心思路就是让每个点击事件都能绑定到当前循环的单元格引用,而不是最后一个。
内容的提问来源于stack exchange,提问作者Anna F
相关产品推荐
相关产品推荐

