JavaScript实现多输入框剩余百分比分配的功能求助
需求与现有问题
需要实现一个百分比分配功能,包含多个可输入0-100数值的输入框,规则如下:
- 若第一个输入框输入100,其余输入框无法输入数值
- 若第一个输入框输入80,第二个输入框自动设为20且不能超过20;若第二个输入框输入15,剩余5自动分配给第三个输入框
- 当前有4个输入框,未来可能增加数量
现有代码存在硬编码输入框数量的问题,无法适配后续扩展,需完善逻辑使其支持动态数量的输入框。
改进后的代码实现
核心JavaScript函数
function updatePayments() { // 动态获取所有输入框并按ID排序,保证顺序正确 const inputElements = Array.from(document.querySelectorAll('input[id^="in-line"]')) .sort((a, b) => { const numA = parseInt(a.id.replace('in-line', '')); const numB = parseInt(b.id.replace('in-line', '')); return numA - numB; }); // 转换为数值数组,空值或非数字设为0 let payments = inputElements.map(el => parseInt(el.value) || 0); const totalInputCount = payments.length; // 处理第一个输入框≥100的情况 if (payments[0] >= 100) { payments = payments.map((val, idx) => idx === 0 ? 100 : 0); // 禁用其余输入框,启用第一个 inputElements.forEach((el, idx) => { el.disabled = idx !== 0; el.value = payments[idx]; }); } else { // 启用所有输入框 inputElements.forEach(el => el.disabled = false); let remainingPercent = 100 - payments[0]; // 前n-1个输入框手动输入,限制不超过剩余值 for (let i = 1; i < totalInputCount - 1; i++) { if (payments[i] > remainingPercent) { payments[i] = remainingPercent; } remainingPercent -= payments[i]; } // 最后一个输入框自动分配剩余值 payments[totalInputCount - 1] = remainingPercent; // 动态设置第二个输入框的最大值 if (totalInputCount >= 2) { inputElements[1].max = 100 - payments[0]; } } // 更新所有输入框的值 inputElements.forEach((el, idx) => { el.value = payments[idx]; }); // 更新金额显示与总金额验证 const poNetTotalValue = parseFloat(GetPoNetTotalValue()); let totalPayments = 0; inputElements.forEach((el, idx) => { const amount = (payments[idx] / 100) * poNetTotalValue; document.getElementById(`out-line${idx + 1}`).textContent = formatNumber(amount); totalPayments += amount; }); // 处理浮点精度问题,验证总金额 const submitButton = document.getElementById('btn-submit'); if (Math.abs(totalPayments - poNetTotalValue) > 0.01) { $('#payment-check-validation').removeClass('visually-hidden'); submitButton.disabled = true; } else { $('#payment-check-validation').addClass('visually-hidden'); submitButton.disabled = false; } $('#out-lines-total').textContent = formatNumber(totalPayments); }
调整后的输入框限制函数
function enforceMinMax(el) { if (el.disabled) return; // 禁用状态下不处理 if (el.value === "") return; const min = parseInt(el.min); const max = parseInt(el.max); let value = parseInt(el.value); if (isNaN(value)) value = min; if (value < min) value = min; if (value > max) value = max; if (parseInt(el.value) !== value) { el.value = value; el.dispatchEvent(new Event("input")); } }
保留的补充函数
function GetPoNetTotalValue() { return document.getElementById('poNetTotal').dataset.poNetTotalValue; } function formatNumber(num) { return num.toLocaleString('en-US', { maximumFractionDigits: 2 }); }
HTML结构(支持动态扩展)
<tbody> <!-- line1: down payment --> <tr> <td width="50%"> Down Payment <input type="hidden" asp-for="PoPayments[0].Notes" value="Down Payment"/> </td> <td width="20%"> <input id="in-line1" asp-for="PoPayments[0].Percentage" type="number" min="0" max="100" class="w-100" placeholder="%" oninput="enforceMinMax(this); updatePayments()" /> </td> <td> <span id="out-line1" data-down-payment-value="0"> 0 </span> </td> </tr> <!-- line2: upon delivery --> <tr> <td width="50%"> Upon Delivery <input type="hidden" asp-for="PoPayments[1].Notes" value="Upon Delivery" /> </td> <td width="20%"> <input id="in-line2" asp-for="PoPayments[1].Percentage" type="number" min="0" max="100" class="w-100" placeholder="%" oninput="enforceMinMax(this); updatePayments()"> </td> <td> <span id="out-line2" data-upon-delivery-value="0"> 0 </span> </td> </tr> <!-- line3: criteria1 --> <tr> <td width="50%"> <input type="text" asp-for="PoPayments[2].Notes" placeholder="Enter Payment Criteria"> </td> <td width="20%"> <input id="in-line3" asp-for="PoPayments[2].Percentage" type="number" min="0" max="100" class="w-100" placeholder="%" oninput="enforceMinMax(this); updatePayments()"> </td> <td> <span id="out-line3" data-criteria1-value="0"> 0 </span> </td> </tr> <!-- line4: criteria2 --> <tr> <td width="50%"> <input type="text" asp-for="PoPayments[3].Notes" placeholder="Enter Payment Criteria"> </td> <td width="20%"> <input id="in-line4" asp-for="PoPayments[3].Percentage" type="number" min="0" max="100" class="w-100" placeholder="%" oninput="enforceMinMax(this); updatePayments()"> </td> <td> <span id="out-line4" data-criteria2-value="0"> 0 </span> </td> </tr> <!-- 未来新增行示例,只需保持id格式为in-lineN、out-lineN即可 --> <!-- <tr> <td width="50%"> <input type="text" asp-for="PoPayments[4].Notes" placeholder="Enter Payment Criteria"> </td> <td width="20%"> <input id="in-line5" asp-for="PoPayments[4].Percentage" type="number" min="0" max="100" class="w-100" placeholder="%" oninput="enforceMinMax(this); updatePayments()"> </td> <td> <span id="out-line5" data-criteria3-value="0"> 0 </span> </td> </tr> --> </tbody>
关键改进说明
- 动态适配输入框数量:通过选择器批量获取输入框,按ID排序保证顺序,新增输入框无需修改核心逻辑
- 规则严格执行:
- 第一个输入框≥100时自动锁定其余输入框
- 动态限制第二个输入框的最大值,符合"第一个输入80则第二个最多20"的规则
- 前n-1个输入框手动输入,最后一个自动分配剩余百分比
- 细节优化:处理浮点精度问题避免验证错误,跳过禁用状态的输入框操作
- 扩展性:新增输入框只需保持
in-lineN、out-lineN的ID格式即可自动适配
内容的提问来源于stack exchange,提问作者Taher
相关产品推荐
相关产品推荐

