DataTable输入字段更新与输入变更时自动计算总计及新增行合计问题
解决DataTables+Handlebars发票表格的自动计算与新增行问题
我帮你梳理下核心问题,然后给出完整的解决方案,搞定输入变化自动计算小计、汇总总价,以及新增行同步计算的难题:
问题分析
你的原代码里有几个关键的坑导致功能异常:
- 所有输入框用了重复的
id,DOM选择会混乱 - 新增行的HTML没有绑定计算逻辑,也没和数据数组同步
onEdit函数逻辑错误,没有实际处理计算- 缺少页脚区域来展示汇总结果
修改后的完整代码
HTML部分(含汇总页脚)
<table width="100%" class="table table-striped table-bordered table-hover" id="example"> <thead> <tr> <th>Article</th> <th>Description</th> <th>Qté commandée</th> <th>Prix unitaire</th> <th>Taxes</th> <th>Sous-total</th> </tr> </thead> <tbody> {{#each facture.facture}} <tr class="data-row"> <td><input type="text" name="article" class="article-input" value="{{article}}"></td> <td><input type="text" name="desc" class="desc-input" value="{{desc}}"></td> <td><input type="number" name="quantity" class="quantity-input" value="{{quantity}}" min="0" step="0.01"></td> <td><input type="number" name="price" class="price-input" value="{{price}}" min="0" step="0.01"></td> <td><input type="number" name="tax" class="tax-input" value="{{tax}}" min="0" step="0.01"></td> <td><input type="text" name="totalHT" class="total-input" value="{{total}}" disabled></td> </tr> {{/each}} </tbody> <tfoot> <tr> <td colspan="4" class="text-right"><strong>Total HT:</strong></td> <td><strong><span id="total-tax">0.00</span></strong></td> <td><strong><span id="grand-total">0.00</span></strong></td> </tr> </tfoot> </table> <button id="add-row-btn" class="btn btn-primary mt-3">Ajouter une ligne</button>
JavaScript部分
<script> // 全局数据数组,同步表格UI和数据 let rowsData = []; $(document).ready(function () { // 初始化DataTables,禁用排序避免输入时表格跳动 const table = $('#example').DataTable({ "bLengthChange": false, "searching": false, "paging": false, "ordering": false }); // 加载初始表格数据到数组 fetchTableData(); // 初始化汇总计算 calcGrandTotal(); // 监听数量、单价、税费输入变化,实时计算 $('#example tbody').on('input', '.quantity-input, .price-input, .tax-input', function () { const currentRow = $(this).closest('tr'); calcRowTotal(currentRow); calcGrandTotal(); updateRowsData(currentRow); }); // 新增行按钮事件 $('#add-row-btn').on('click', function () { addEmptyRow(table); }); }); // 从表格加载初始数据到rowsData function fetchTableData() { rowsData = []; $('.data-row').each(function(index) { const $row = $(this); rowsData.push({ article: $row.find('.article-input').val(), desc: $row.find('.desc-input').val(), quantity: parseFloat($row.find('.quantity-input').val()) || 0, price: parseFloat($row.find('.price-input').val()) || 0, tax: parseFloat($row.find('.tax-input').val()) || 0, total: parseFloat($row.find('.total-input').val()) || 0 }); }); } // 更新单行数据到rowsData function updateRowsData(row) { const rowIndex = row.index(); rowsData[rowIndex] = { article: row.find('.article-input').val(), desc: row.find('.desc-input').val(), quantity: parseFloat(row.find('.quantity-input').val()) || 0, price: parseFloat(row.find('.price-input').val()) || 0, tax: parseFloat(row.find('.tax-input').val()) || 0, total: parseFloat(row.find('.total-input').val()) || 0 }; } // 计算单行的Sous-total(数量*单价) function calcRowTotal(row) { const quantity = parseFloat(row.find('.quantity-input').val()) || 0; const price = parseFloat(row.find('.price-input').val()) || 0; const total = (quantity * price).toFixed(2); row.find('.total-input').val(total); } // 计算全局汇总:所有行小计总和 + 税费总和 function calcGrandTotal() { let totalHT = 0; let totalTax = 0; $('.data-row').each(function() { totalHT += parseFloat($(this).find('.total-input').val()) || 0; totalTax += parseFloat($(this).find('.tax-input').val()) || 0; }); const grandTotal = (totalHT + totalTax).toFixed(2); $('#total-tax').text(totalTax.toFixed(2)); $('#grand-total').text(grandTotal); } // 新增空行并同步数据 function addEmptyRow(table) { const newRowHtml = ` <tr class="data-row"> <td><input type="text" name="article" class="article-input" value=""></td> <td><input type="text" name="desc" class="desc-input" value=""></td> <td><input type="number" name="quantity" class="quantity-input" value="0" min="0" step="0.01"></td> <td><input type="number" name="price" class="price-input" value="0" min="0" step="0.01"></td> <td><input type="number" name="tax" class="tax-input" value="0" min="0" step="0.01"></td> <td><input type="text" name="totalHT" class="total-input" value="0.00" disabled></td> </tr> `; table.row.add($(newRowHtml)).draw(); // 同步数据数组 rowsData.push({ article: '', desc: '', quantity: 0, price: 0, tax: 0, total: 0 }); } </script>
关键修改说明
- 替换重复ID为Class:把所有输入框的
id改成class,避免DOM选择冲突,确保每行输入框都能被准确定位。 - 新增汇总页脚:添加
<tfoot>区域展示税费总和与最终总价,让结果一目了然。 - 拆分计算逻辑:
calcRowTotal:单独处理单行小计计算,只在数量/单价变化时触发calcGrandTotal:遍历所有行汇总数据,实时更新页脚
- 同步数据与UI:每次输入变化或新增行时,都会更新
rowsData数组,确保数据和界面完全同步。 - 优化输入体验:把数字类输入框改成
type="number",设置min="0"和step="0.01",限制非数字输入,方便用户操作。 - 完善新增行逻辑:新增行时插入完整的HTML结构,同时同步更新数据数组,确保新行也能触发计算事件。
这样修改后,不管是编辑现有行还是新增行,都会自动计算每行小计,并且实时更新页脚的汇总总价,完美解决你的问题!
内容的提问来源于stack exchange,提问作者hamdi islam
相关产品推荐
相关产品推荐

