You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

原生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;
}

关键修改说明

  1. 移除重复事件绑定:将table的change监听器移到addRow函数外,只绑定一次,避免事件叠加触发多次新增。
  2. 行状态标记:用data-processed属性标记行是否已触发过新增逻辑,防止同一行重复触发。
  3. ID生成优化:在addRow末尾递增rowNumber,确保每行输入框ID唯一。
  4. 数据存储:输入完成后直接将数据存入names数组,方便后续分组逻辑使用。

内容的提问来源于stack exchange,提问作者That New Coder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 20:45:10