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

JavaScript计算函数在循环生成的表格行中仅第一行生效

解决PHP循环生成表格行中总价计算仅第一行生效的问题

这问题我见得挺多的,核心原因很明确:你在循环里给所有行的输入框都用了相同的id属性,而document.getElementById()只会返回页面中第一个匹配该id的元素。所以不管你在第几行输入,代码永远只会拿第一行的unit_rate、quantity和total_price来计算,后续行自然就没反应了。

下面给你两个可行的解决方案,按需选择:

方案一:给元素添加唯一标识(基于循环计数器)

先修改你的PHP代码,给每个输入框的id和name加上循环计数器后缀,同时把onKeyUp的调用改成传递当前元素的引用,这样能精准定位到触发事件的行:

<?php $counter = 0; foreach($db->getRecordSet($sqlTrRecord) as $row){$counter += 1; ?>
<tr class="banktblhd">
<td width="5"><?php echo($counter); ?></td>
<td class="w10"><input type="text" name="item_code_<?php echo $counter; ?>" id="item_code_<?php echo $counter; ?>" class="form-control" value="<?php echo($row['item_code']); ?>" readonly /></td>
<td class="w20"><input type="text" class="form-control" name="item_name_<?php echo $counter; ?>" id="item_name_<?php echo $counter; ?>" value="<?php echo($row['item_name']); ?>" readonly /></td>
<td class="w10"><input type="text" class="form-control" name="description_<?php echo $counter; ?>" id="description_<?php echo $counter; ?>" value="<?php echo($row['description']); ?>" readonly /></td>
<td class="w10"><input type="text" class="form-control" name="availableQty_<?php echo $counter; ?>" id="availableQty_<?php echo $counter; ?>" value="<?php echo($row['quantity']); ?>" readonly /></td>
<td class="w10"><input type="text" class="form-control" name="unit_rate_<?php echo $counter; ?>" id="unit_rate_<?php echo $counter; ?>" onKeyUp="total(this)" value="<?php echo($row['unit_rate']); ?>" readonly /></td>
<td class="w10"><input type="number" class="form-control" name="quantity_<?php echo $counter; ?>" id="quantity_<?php echo $counter; ?>" onKeyUp="total(this)" autocomplete="off" /></td>
<td class="w10"><input type="text" class="form-control" name="total_price_<?php echo $counter; ?>" id="total_price_<?php echo $counter; ?>" value="" /></td>
</tr>
<?php } ?>

然后修改total函数,通过传入的元素找到它所在的表格行,再在该行内查找对应的输入框:

function total(element) {
    // 定位当前输入框所在的表格行
    const currentRow = element.closest('tr');
    // 获取当前行的计数器值
    const rowNum = currentRow.querySelector('td:first-child').textContent;
    
    // 在当前行内找到对应的单价、数量、总价输入框
    const unitRateInput = currentRow.querySelector(`#unit_rate_${rowNum}`);
    const quantityInput = currentRow.querySelector(`#quantity_${rowNum}`);
    const totalPriceInput = currentRow.querySelector(`#total_price_${rowNum}`);
    
    // 处理空值或非数字的情况,避免出现NaN
    const unitRate = parseFloat(unitRateInput.value) || 0;
    const quantity = parseFloat(quantityInput.value) || 0;
    
    // 计算并赋值总价,可根据需求保留小数位数
    totalPriceInput.value = (unitRate * quantity).toFixed(2);
}

方案二:使用class定位(更简洁,推荐)

如果不想处理带后缀的id,可以给需要计算的输入框加上专属class,同时把name改成数组形式(方便后续表单提交批量获取数据):

<?php $counter = 0; foreach($db->getRecordSet($sqlTrRecord) as $row){$counter += 1; ?>
<tr class="banktblhd">
<td width="5"><?php echo($counter); ?></td>
<td class="w10"><input type="text" name="item_code[]" class="form-control" value="<?php echo($row['item_code']); ?>" readonly /></td>
<td class="w20"><input type="text" class="form-control" name="item_name[]" value="<?php echo($row['item_name']); ?>" readonly /></td>
<td class="w10"><input type="text" class="form-control" name="description[]" value="<?php echo($row['description']); ?>" readonly /></td>
<td class="w10"><input type="text" class="form-control" name="availableQty[]" value="<?php echo($row['quantity']); ?>" readonly /></td>
<td class="w10"><input type="text" class="form-control unit-rate" name="unit_rate[]" onKeyUp="total(this)" value="<?php echo($row['unit_rate']); ?>" readonly /></td>
<td class="w10"><input type="number" class="form-control quantity" name="quantity[]" onKeyUp="total(this)" autocomplete="off" /></td>
<td class="w10"><input type="text" class="form-control total-price" name="total_price[]" value="" /></td>
</tr>
<?php } ?>

对应的total函数会更简洁,完全依赖class定位当前行的元素:

function total(element) {
    const currentRow = element.closest('tr');
    
    const unitRate = parseFloat(currentRow.querySelector('.unit-rate').value) || 0;
    const quantity = parseFloat(currentRow.querySelector('.quantity').value) || 0;
    
    currentRow.querySelector('.total-price').value = (unitRate * quantity).toFixed(2);
}

这个方案的优势在于代码更干净,后续表单提交时,后端可以直接通过$_POST['unit_rate']这种数组形式获取所有行的数据,不用再逐个处理带后缀的字段名。

内容的提问来源于stack exchange,提问作者Sikandar Khan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:55:05