动态输入表格添加下拉框并实现多变量值与多总计计算
问题描述
现有一套可动态增删行的输入表格,运行状态良好,需要实现以下需求:
- 为表格添加更多下拉选择框
- 将
<select>的value属性从原本的数字改为包含多个变量的对象,以此计算出多个维度的总计结果
此前尝试用switch-case语句绑定变量但未生效,希望找到更简洁易维护的实现方式。
解决方案
核心思路是用产品数据映射表替代繁琐的switch-case,将每个产品对应的多属性值统一管理,同时修复原代码中遍历目标错误、逻辑分散的问题。
1. 定义产品数据映射表
把每个产品对应的各维度数值(总价、pencil、ruler、highlighter)存入一个对象,后续新增/修改产品只需更新这个映射表,无需改动逻辑代码:
const productData = { product1: { price: 10, pencil: 10, ruler: 11, highlighter: 13 }, product2: { price: 14, pencil: 14, ruler: 16, highlighter: 17 }, product3: { price: 18, pencil: 18, ruler: 19, highlighter: 20 }, product4: { price: 22, pencil: 22, ruler: 23, highlighter: 25 }, product5: { price: 26, pencil: 26, ruler: 27, highlighter: 29 }, product6: { price: 30, pencil: 30, ruler: 31, highlighter: 33 } };
2. 修改HTML结构
- 移除冗余的
<select>代码,确保模板结构统一 - 给下拉框选项的
value设置为映射表对应的产品key:
<button id="btn-add-row">Add new row</button> <table id="my-table"> <thead> <tr> <th>Quantity</th> <th>Product</th> <th>Total</th> <th></th> </tr> </thead> <tbody></tbody> <tfoot> <tr> <td colspan="3"> TOTAL = <input type="text" name="anstotal" value="0" readonly></td> <td></td> </tr> </tfoot> </table> <template id="template-row"> <tr> <td><input type="number" name="qty" value="0" min="0"></td> <td> <select name="sel"> <option value="" disabled selected>Choose a product</option> <option value="product1">Product one</option> <option value="product2">Product two</option> <option value="product3">Product three</option> <option value="product4">Product four</option> <option value="product5">Product five</option> <option value="product6">Product six</option> </select> </td> <td><input type="text" name="total" value="0" readonly></td> <td><button name="delete-row">Delete</button></td> </tr> </template> <div class="product_total"> <div>Pencil: <span id="pencil">0</span></div> <div>Ruler: <span id="ruler">0</span></div> <div>Highlighter: <span id="highlighter">0</span></div> </div>
3. 重构JS逻辑
合并原有的setTotals和calc函数,统一在输入变化时计算所有总计,同时修正原代码中遍历模板元素的错误:
const myTable_tBody = document.querySelector('#my-table tbody'); const templateRow = document.querySelector('#template-row'); const myTable_Total = document.querySelector('#my-table tfoot input[name="anstotal"]'); const pencilTotalEl = document.getElementById('pencil'); const rulerTotalEl = document.getElementById('ruler'); const highlighterTotalEl = document.getElementById('highlighter'); // 产品数据映射表 const productData = { product1: { price: 10, pencil: 10, ruler: 11, highlighter: 13 }, product2: { price: 14, pencil: 14, ruler: 16, highlighter: 17 }, product3: { price: 18, pencil: 18, ruler: 19, highlighter: 20 }, product4: { price: 22, pencil: 22, ruler: 23, highlighter: 25 }, product5: { price: 26, pencil: 26, ruler: 27, highlighter: 29 }, product6: { price: 30, pencil: 30, ruler: 31, highlighter: 33 } }; // 初始化第一行 AddNewRow(); // 绑定事件 document.querySelector('#btn-add-row').addEventListener('click', AddNewRow); myTable_tBody.addEventListener('input', calculateAllTotals); myTable_tBody.addEventListener('click', e => { if (e.target.matches('button[name="delete-row"]')) { e.target.closest('tr').remove(); calculateAllTotals(); } }); // 统一计算所有总计 function calculateAllTotals() { let grandTotal = 0; let totalPencil = 0; let totalRuler = 0; let totalHighlighter = 0; [...myTable_tBody.rows].forEach(row => { const qty = row.querySelector('input[name="qty"]').valueAsNumber || 0; const productKey = row.querySelector('select[name="sel"]').value; const product = productData[productKey] || { price: 0, pencil: 0, ruler: 0, highlighter: 0 }; // 计算当前行的总价 const rowTotal = qty * product.price; row.querySelector('input[name="total"]').value = rowTotal; // 累加所有总计 grandTotal += rowTotal; totalPencil += qty * product.pencil; totalRuler += qty * product.ruler; totalHighlighter += qty * product.highlighter; }); // 更新页面显示 myTable_Total.value = grandTotal; pencilTotalEl.textContent = totalPencil; rulerTotalEl.textContent = totalRuler; highlighterTotalEl.textContent = totalHighlighter; } // 添加新行 function AddNewRow() { if (myTable_tBody.rows.length < 4) { myTable_tBody.append(document.importNode(templateRow.content, true)); } else { alert("Maximum Passenger per ticket is 4."); } }
方案优势
- 易维护:新增产品只需在
productData中添加对应条目,无需修改逻辑代码 - 逻辑统一:把分散的计算逻辑合并,减少重复操作
- 错误处理:针对未选择产品的情况做了默认值处理,避免NaN错误
- 扩展性强:后续要新增更多维度的统计,只需在映射表和计算逻辑中添加对应字段即可
内容的提问来源于stack exchange,提问作者Bouali Ramzi
相关产品推荐
相关产品推荐

