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

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>

关键改进说明
  1. 动态适配输入框数量:通过选择器批量获取输入框,按ID排序保证顺序,新增输入框无需修改核心逻辑
  2. 规则严格执行:
    • 第一个输入框≥100时自动锁定其余输入框
    • 动态限制第二个输入框的最大值,符合"第一个输入80则第二个最多20"的规则
    • 前n-1个输入框手动输入,最后一个自动分配剩余百分比
  3. 细节优化:处理浮点精度问题避免验证错误,跳过禁用状态的输入框操作
  4. 扩展性:新增输入框只需保持in-lineN、out-lineN的ID格式即可自动适配

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 00:44:54