输入框格式化货币后如何保持光标在原字符位置?
解决货币格式化后光标位置偏移问题
问题描述
我有一个用于输入数字的输入框,通过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." }
关键说明
- 忽略特定按键:避免在移动光标、删除字符时触发格式化,减少不必要的光标调整操作。
- 记录光标位置:使用
input.selectionStart获取当前光标起始位置(输入时光标起始和结束位置一致)。 - 计算偏移量:由于格式化会添加千分位分隔符(
.)、小数分隔符(,)和后缀kr.,这些非数字字符会改变字符串长度。通过对比原字符串和格式化后字符串中,光标位置前的非数字字符数量差,来调整光标位置。 - 边界处理:确保计算后的光标位置不会超出字符串的首尾范围,避免设置无效的光标位置。
内容的提问来源于stack exchange,提问作者Sina Sohi
相关产品推荐
相关产品推荐

