原生JS实现每次仅添加一行表格的解决方案
问题分析与解决方案
你的问题出在重复绑定事件监听器上:每次调用addRow()时,都会给table元素新增一个change事件监听器。当你添加第2行后,table上已经绑定了2个监听器,触发change事件时两个监听器都会执行,所以会新增2行。
修复方案
核心思路是只给table绑定一次change事件,然后在事件回调里定位当前触发事件的输入框所在的行,检查该行的两个输入框是否都已填写,再决定是否新增行。同时调整rowNumber的递增逻辑,确保ID唯一。
修正后的完整代码
JavaScript 部分
const inputArticle = document.querySelector('#input-article'); const outputArticle = document.querySelector('#output-article'); const table = document.querySelector('#table'); const addRowButton = document.querySelector('#addRow'); const submitButton = document.querySelector('#submit'); let names = []; let rowNumber = 0; function addRow() { let row = table.insertRow(-1); // 给行加标识,避免重复触发新增 row.dataset.processed = 'false'; let cell1 = row.insertCell(0); let cell2 = row.insertCell(1); let firstNameInput = document.createElement("input"); let lastNameInput = document.createElement("input"); firstNameInput.type = "text"; firstNameInput.setAttribute('id', `firstName${rowNumber}`); cell1.appendChild(firstNameInput); lastNameInput.type = "text"; lastNameInput.setAttribute('id', `lastName${rowNumber}`); cell2.appendChild(lastNameInput); rowNumber++; } // 只绑定一次change事件 table.addEventListener('change', (e) => { // 定位当前输入框所在行,跳过表头 const currentRow = e.target.closest('tr'); if (!currentRow || currentRow.querySelector('th')) return; // 跳过已处理过的行 if (currentRow.dataset.processed === 'true') return; const firstNameInput = currentRow.querySelector('input[id^="firstName"]'); const lastNameInput = currentRow.querySelector('input[id^="lastName"]'); // 检查两个输入框是否都有非空值 if (firstNameInput.value.trim() && lastNameInput.value.trim()) { currentRow.dataset.processed = 'true'; addRow(); // 将当前行数据存入数组 names.push({ firstName: firstNameInput.value.trim(), lastName: lastNameInput.value.trim() }); } }) function submit() { let confirmation = confirm("Are you sure you have all of the names?"); if (confirmation) { inputArticle.classList.add("hidden"); outputArticle.classList.remove("hidden"); console.log('已收集的名字:', names); } } addRowButton.addEventListener('click', () => { addRow(); addRowButton.disabled = true; }) inputArticle.classList.remove("hidden"); outputArticle.classList.add("hidden"); submitButton.addEventListener('click', submit);
HTML 部分
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE-edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="author" content="Christian Davis"> <link rel="stylesheet" href="styles.css"> <title>Random Group Generator</title> </head> <body> <article id="input-article"> <table id="table" border="1"> <tr> <th>First Name:</th> <th>Last Name:</th> </tr> </table> <br> <div id="buttons"> <button id="addRow">Add Row</button> <button id="submit">Submit</button> </div> </article> <article id="output-article"> Output </article> <script src="try.js"></script> </body> </html>
CSS 部分
#input-article.hidden { display: none; } table { text-align: center; align-items: center; } th { width: 50vmin; height: 10vmin; font-size: 20pt; font-weight: 800; } input { width: 50vmin; height: 5vmin; text-align: center; align-items: center; font-size: 18pt; font-weight: 400; font-family: Georgia, 'Times New Roman', Times, serif; border: 0; padding: 0; } #buttons { width: 100vmin; height: 10vmin; } #submit { background-color: blue; color: white; border: 0; position: relative; left: 84%; } #output-article.hidden { display: none; }
关键修改说明
- 移除重复事件绑定:将
table的change监听器移到addRow函数外,只绑定一次,避免事件叠加触发多次新增。 - 行状态标记:用
data-processed属性标记行是否已触发过新增逻辑,防止同一行重复触发。 - ID生成优化:在
addRow末尾递增rowNumber,确保每行输入框ID唯一。 - 数据存储:输入完成后直接将数据存入
names数组,方便后续分组逻辑使用。
内容的提问来源于stack exchange,提问作者That New Coder
相关产品推荐
相关产品推荐

