如何为表格添加新行并在输入价格后自动计算金额(数量×单价)
实现产品表格自动计算金额并动态添加行的解决方案
我帮你梳理并解决这个问题,原代码存在几个关键问题(比如全局变量导致行数据冲突、添加行逻辑不完整、输入类型错误等),下面是修改后的完整实现和详细解释:
修改后的完整代码
<table id="products_table" class="table table-hover" name="products"> <thead> <tr> <th scope="col">Name</th> <th scope="col">Quantity</th> <th scope="col">Pieces</th> <th scope="col">Price</th> <th scope="col">Amount</th> </tr> </thead> <tbody> <!-- 模板行:隐藏起来作为克隆原型,避免初始显示重复内容 --> <tr class="template-row" id="templateRow" style="display:none"> <td> <select style="margin-left:20px" name="product_id"> <?php while($r = mysqli_fetch_assoc($presult)) { ?> <option value="<?php echo $r["id"]?>"><?php echo $r["name"]?></option> <?php } ?> </select> </td> <td><input type="number" name="quantity" step="0.01" oninput="calculateAmount(this)"></td> <td><input type="number" name="pieces" step="0.01"></td> <td><input type="number" name="price" step="0.01" oninput="calculateAmount(this)"></td> <td><input type="text" name="amount" readonly></td> </tr> <!-- 初始显示的第一行产品 --> <tr class="product-row"> <td> <select style="margin-left:20px" name="product_id"> <?php while($r = mysqli_fetch_assoc($presult)) { ?> <option value="<?php echo $r["id"]?>"><?php echo $r["name"]?></option> <?php } ?> </select> </td> <td><input type="number" name="quantity" step="0.01" oninput="calculateAmount(this)"></td> <td><input type="number" name="pieces" step="0.01"></td> <td><input type="number" name="price" step="0.01" oninput="calculateAmount(this)"></td> <td><input type="text" name="amount" readonly></td> </tr> </tbody> </table> <script> // 计算当前行的金额,并自动添加新行 function calculateAmount(element) { // 获取当前输入框所在的产品行 const row = element.closest('.product-row'); if (!row) return; // 提取当前行的数量和单价(默认值为0,避免NaN) const quantity = parseFloat(row.querySelector('input[name="quantity"]').value) || 0; const price = parseFloat(row.querySelector('input[name="price"]').value) || 0; // 计算金额并填充到对应输入框,保留两位小数 const amount = quantity * price; row.querySelector('input[name="amount"]').value = amount.toFixed(2); // 自动添加新行:仅当当前是最后一行,且数量和单价都有有效值时触发 const tableBody = document.querySelector('#products_table tbody'); const lastRow = tableBody.querySelector('.product-row:last-child'); if (row === lastRow && quantity > 0 && price > 0) { addNewRow(); } } // 克隆模板行并添加到表格末尾 function addNewRow() { const templateRow = document.querySelector('#templateRow'); const tableBody = document.querySelector('#products_table tbody'); // 克隆模板行(true表示克隆所有子元素) const newRow = templateRow.cloneNode(true); // 移除模板行的ID,避免DOM中出现重复ID newRow.removeAttribute('id'); // 显示新行(模板行默认是隐藏的) newRow.style.display = ''; // 添加产品行类,方便后续关联 newRow.classList.add('product-row'); // 清空新行的所有输入框值,避免继承模板行的内容 const inputs = newRow.querySelectorAll('input'); inputs.forEach(input => input.value = ''); // 将新行添加到表格tbody的末尾 tableBody.appendChild(newRow); } </script>
关键改进点说明
- 修正输入框类型:把原代码的
type="float"改为type="number"(HTML中没有float类型的输入框),并添加step="0.01"支持小数输入,提升用户体验。 - 移除全局变量,实现行独立计算:不再用全局变量存储数量,而是通过
element.closest('.product-row')定位当前输入框所在的行,确保每行的数量和价格都是独立计算,不会互相干扰。 - 自动计算并填充金额:当数量或单价发生变化时,自动计算金额并填充到对应输入框,同时设置金额输入框为
readonly,避免用户手动修改,保证数据准确性。 - 智能添加新行:仅当最后一行的数量和单价都输入有效值时,自动克隆模板行添加到表格末尾,用户无需手动操作即可继续输入下一个产品。
- 模板行复用:将原模板行隐藏,作为克隆的原型,避免初始页面显示重复的下拉框内容,同时保证新行的结构和初始行完全一致。
内容的提问来源于stack exchange,提问作者Kamal Kannan




