如何解决JavaScript实现MySQL记录删除按钮的报错问题
MySQL表镜像页面删除按钮功能异常
场景概述
我正在构建一个用于镜像MySQL服务器中某张表的网页,表格每行配有两个按钮,其中红色按钮用于删除服务器中的对应记录。页面效果为:表格展示了MySQL表中的数据,包含Código、Tipo de Movimento等列,每行末尾配有绿色确认按钮和红色删除按钮。
现有实现代码
数据加载与表格生成代码
async function loadData(){ var result = await fetch("http://localhost:8080/dados", { method:"POST", headers:{'Content-Type': "application/json"}, body:JSON.stringify({command: "fetch", codMovimento: 0}) } ) tableJson = await result.json() console.log(tableJson) var table = document.getElementById("minhaTabela"); table.innerHTML += "<tbody>" table.innerHTML += `<thead class="thead-dark"> <tr> <th scope="col">Código</th> <th scope="col">Tipo de Movimento</th> <th scope="col">Técnico</th> <th scope="col" style="width:350px;">Peça</th> <th scope="col">Código da Peça</th> <th scope="col">Origem</th> <th scope="col">Destino</th> <th scope="col" style="text-align: center;">Quantidade</th> <th scope="col"></th> <th scope="col"></th> </tr> </thead>` for(var i=0; i < tableJson.length; i++){ table.innerHTML += ` <tr> <th scope="row">${tableJson[i].CodMovimento}</th> <td>${tableJson[i].TipoMovimento}</td> <td>${tableJson[i].Tecnico}</td> <td>${tableJson[i].NomePeca}</td> <td>${tableJson[i].CodPeca}</td> <td>${tableJson[i].Origem}</td> <td>${tableJson[i].Destino}</td> <td style="text-align: center;">1</td> <td> <button type="button" class="btn btn-success" id="approveButton${i}"> <img src="/assets/check.svg" alt="Bootstrap" width="32" height="32"> </button> </td> <td> <button type="button" class="btn btn-danger" id="refuseButton${i}"> <img src="/assets/x.svg" alt="Bootstrap" width="32" height="32"> </button> </td> </tr> ` } table.innerHTML += "</tbody>" declareButtons(tableJson) } loadData()
删除按钮绑定代码
async function declareButtons(tableJson){ const approveButtons = [] const refuseButtons = [] for(var i=0; i < tableJson.length; i++){ approveButtons.push(document.getElementById(`approveButton${i}`)); approveButtons[i].onclick = async function(){ console.log("Teste234") } refuseButtons.push(document.getElementById(`refuseButton${i}`)); refuseButtons[i].onclick = async function(tableJson){ console.log(tableJson[i].CodMovimento) var result = await fetch("http://localhost:8080/dados", { method:"POST", headers:{'Content-Type': "application/json"}, body:JSON.stringify({command: "delete", codMovimento: tableJson[i].CodMovimento}) } ) location.reload() } } }
问题现象
点击红色删除按钮时,控制台抛出Uncaught TypeError: Cannot read properties of undefined (reading 'CodMovimento')错误;添加try/catch块后报错不再显示,但删除记录的逻辑仍未执行。
解决方案
问题根源
- 闭包陷阱:使用
var声明循环变量i,所有点击函数共享同一个i引用,点击时i已变为循环结束后的最大值,导致tableJson[i]为undefined。 - 参数覆盖:点击函数的参数
tableJson覆盖了外部作用域的同名变量,内部访问的不是原数据数组。
修复方案1:修复闭包与参数问题
async function declareButtons(tableJson){ const approveButtons = [] const refuseButtons = [] // 用let声明i,每次循环创建独立作用域 for(let i=0; i < tableJson.length; i++){ approveButtons.push(document.getElementById(`approveButton${i}`)); approveButtons[i].onclick = async function(){ console.log("Teste234") } refuseButtons.push(document.getElementById(`refuseButton${i}`)); // 移除多余的tableJson参数,避免覆盖外部变量 refuseButtons[i].onclick = async function(){ const codMovimento = tableJson[i].CodMovimento; console.log(codMovimento); try { const result = await fetch("http://localhost:8080/dados", { method:"POST", headers:{'Content-Type': "application/json"}, body:JSON.stringify({command: "delete", codMovimento: codMovimento}) } ); // 检查请求是否成功 if(!result.ok){ throw new Error(`请求失败:${result.status}`); } location.reload(); } catch(err) { console.error("删除失败:", err); // 可在此添加用户友好的错误提示 } } } }
修复方案2:事件委托(更推荐)
无需循环绑定事件,直接在表格上绑定事件监听,通过事件冒泡判断点击目标,避免闭包问题且性能更优:
// 替换原declareButtons函数 function setupTableEvents() { const table = document.getElementById("minhaTabela"); table.addEventListener("click", async function(e) { const targetBtn = e.target.closest("button"); if(!targetBtn) return; // 判断是否为删除按钮 if(targetBtn.classList.contains("btn-danger")){ // 获取当前行的CodMovimento const row = targetBtn.closest("tr"); const codMovimento = row.querySelector("th").textContent; try { const result = await fetch("http://localhost:8080/dados", { method:"POST", headers:{'Content-Type': "application/json"}, body:JSON.stringify({command: "delete", codMovimento: parseInt(codMovimento)}) } ); if(!result.ok){ throw new Error(`请求失败:${result.status}`); } location.reload(); } catch(err) { console.error("删除失败:", err); } } else if(targetBtn.classList.contains("btn-success")){ console.log("Teste234"); } }); } // 在loadData函数中替换declareButtons(tableJson)为: // setupTableEvents();
额外优化建议
- 为
loadData中的tableJson添加局部变量声明:const tableJson = await result.json();,避免污染全局作用域。 - 生成表格时,先构建完整HTML字符串再一次性赋值,减少DOM操作次数:
async function loadData(){ const result = await fetch("http://localhost:8080/dados", { method:"POST", headers:{'Content-Type': "application/json"}, body:JSON.stringify({command: "fetch", codMovimento: 0}) } ) const tableJson = await result.json() console.log(tableJson) const table = document.getElementById("minhaTabela"); let html = `<tbody> <thead class="thead-dark"> <tr> <th scope="col">Código</th> <th scope="col">Tipo de Movimento</th> <th scope="col">Técnico</th> <th scope="col" style="width:350px;">Peça</th> <th scope="col">Código da Peça</th> <th scope="col">Origem</th> <th scope="col">Destino</th> <th scope="col" style="text-align: center;">Quantidade</th> <th scope="col"></th> <th scope="col"></th> </tr> </thead>`; for(let i=0; i < tableJson.length; i++){ html += ` <tr> <th scope="row">${tableJson[i].CodMovimento}</th> <td>${tableJson[i].TipoMovimento}</td> <td>${tableJson[i].Tecnico}</td> <td>${tableJson[i].NomePeca}</td> <td>${tableJson[i].CodPeca}</td> <td>${tableJson[i].Origem}</td> <td>${tableJson[i].Destino}</td> <td style="text-align: center;">1</td> <td> <button type="button" class="btn btn-success"> <img src="/assets/check.svg" alt="Bootstrap" width="32" height="32"> </button> </td> <td> <button type="button" class="btn btn-danger"> <img src="/assets/x.svg" alt="Bootstrap" width="32" height="32"> </button> </td> </tr>`; } html += "</tbody>"; table.innerHTML = html; setupTableEvents(); } loadData()
内容的提问来源于stack exchange,提问作者Linx
相关产品推荐
相关产品推荐

