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

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>

关键修改说明

  1. 替换重复ID为Class:把所有输入框的id改成class,避免DOM选择冲突,确保每行输入框都能被准确定位。
  2. 新增汇总页脚:添加<tfoot>区域展示税费总和与最终总价,让结果一目了然。
  3. 拆分计算逻辑:
    • calcRowTotal:单独处理单行小计计算,只在数量/单价变化时触发
    • calcGrandTotal:遍历所有行汇总数据,实时更新页脚
  4. 同步数据与UI:每次输入变化或新增行时,都会更新rowsData数组,确保数据和界面完全同步。
  5. 优化输入体验:把数字类输入框改成type="number",设置min="0"和step="0.01",限制非数字输入,方便用户操作。
  6. 完善新增行逻辑:新增行时插入完整的HTML结构,同时同步更新数据数组,确保新行也能触发计算事件。

这样修改后,不管是编辑现有行还是新增行,都会自动计算每行小计,并且实时更新页脚的汇总总价,完美解决你的问题!

内容的提问来源于stack exchange,提问作者hamdi islam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:18:23