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

输入框格式化货币后如何保持光标在原字符位置?

解决货币格式化后光标位置偏移问题

问题描述

我有一个用于输入数字的输入框,通过JavaScript将输入内容格式化为丹麦货币格式(例如 1.239.456,50 kr.)。但目前每次格式化后,光标都会跳到输入框末尾,无法停留在原输入字符对应的位置。例如:

  • 输入值:12.3[cursor]45.678,50,输入9后希望变成 123.9[cursor]45.678,50
  • 输入值:123[cursor].456,50,输入9后希望变成 1.239.[cursor]456,50

输入框代码:

<input type="text" class="invoiceFields invoiceDescriptionFields form-control InputStyleForms {% if description_error in form_errors %} is-invalid {% endif %}"
       id="inputDescription-{{id}}" placeholder="Beskrivelse." name="invoiceline-{{id}}-description"
       style="margin-bottom: 8px;" value="{{line.description.value|default_if_none:''}}"
       maxlength="50">

原格式化代码(光标会跳到末尾):

$(document).on('keyup', '.invoiceFields', function () {
    $(this).val(displayInCurrencyFormat($(this).val()));
});

const displayInCurrencyFormat = (value) => {
            value = convertToDanishFloat(value);
            value = value.toString().replace(/(?!\,)\D/g, "").replace(/(?<=\,,*)\,/g, "").replace(/(?<=\,\d\d).*/g, "").replace(/\B(?=(\d{3})+(?!\d))/g, ".");
            if(value.indexOf(",") >= 0){
                // do nothing
            } else {
                value += ",00";
            }
            return value += " kr."
        }

解决方案

核心思路是:格式化前记录光标位置,格式化后根据原位置与新旧字符串的非数字字符差异,计算新的光标位置并手动设置。

修改后的jQuery事件处理代码如下:

$(document).on('keyup', '.invoiceFields', function (e) {
    // 排除方向键、退格、删除等不需要触发格式化的按键
    const ignoredKeys = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Backspace', 'Delete', 'Tab'];
    if (ignoredKeys.includes(e.key)) return;

    const input = this;
    const cursorPos = input.selectionStart;
    const originalVal = input.value;
    const formattedVal = displayInCurrencyFormat(originalVal);

    // 值未变化时无需调整光标
    if (originalVal === formattedVal) return;

    input.value = formattedVal;

    // 计算光标偏移量:统计原字符串和格式化后字符串中,光标位置前的非数字字符数量差
    const originalNonDigits = originalVal.substring(0, cursorPos).replace(/\d/g, '').length;
    const formattedNonDigits = formattedVal.substring(0, cursorPos).replace(/\d/g, '').length;
    let newCursorPos = cursorPos + (formattedNonDigits - originalNonDigits);

    // 确保光标位置在合法范围内(不超出字符串长度,不小于0)
    newCursorPos = Math.max(0, Math.min(newCursorPos, formattedVal.length));
    input.setSelectionRange(newCursorPos, newCursorPos);
});

// 保留原有的格式化函数
const displayInCurrencyFormat = (value) => {
    value = convertToDanishFloat(value);
    value = value.toString().replace(/(?!\,)\D/g, "").replace(/(?<=\,,*)\,/g, "").replace(/(?<=\,\d\d).*/g, "").replace(/\B(?=(\d{3})+(?!\d))/g, ".");
    if (value.indexOf(",") >= 0) {
        // 已有小数部分,无需处理
    } else {
        value += ",00";
    }
    return value += " kr."
}

关键说明

  1. 忽略特定按键:避免在移动光标、删除字符时触发格式化,减少不必要的光标调整操作。
  2. 记录光标位置:使用input.selectionStart获取当前光标起始位置(输入时光标起始和结束位置一致)。
  3. 计算偏移量:由于格式化会添加千分位分隔符(.)、小数分隔符(,)和后缀 kr.,这些非数字字符会改变字符串长度。通过对比原字符串和格式化后字符串中,光标位置前的非数字字符数量差,来调整光标位置。
  4. 边界处理:确保计算后的光标位置不会超出字符串的首尾范围,避免设置无效的光标位置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 21:27:16