
本文介绍一种健壮、用户友好的 javascript 方案,通过监听 contenteditable 元素的输入事件,智能维护光标位置,将数字实时格式化为符合印度数制规范的样式(如 1,00,000 而非 100,000),并规避传统 input + value 操作导致的光标跳转问题。
本文介绍一种健壮、用户友好的 javascript 方案,通过监听 contenteditable 元素的输入事件,智能维护光标位置,将数字实时格式化为符合印度数制规范的样式(如 1,00,000 而非 100,000),并规避传统 input + value 操作导致的光标跳转问题。
在印度本地化金融应用中,数字格式必须遵循印度数制系统:每三位一组从右向左分隔,但前三位与后续组之间为两位(即 1,00,000 表示 1 lakh,1,00,00,000 表示 1 crore)。标准正则 \B(?=(\d{3})+(?!\d)) 仅适配国际千位分隔(如 100,000),无法满足需求。因此,核心前提是先实现正确的印度格式化函数:
function formatIndianNumber(numStr) {
const digits = numStr.replace(/[^0-9]/g, '');
if (!digits) return '';
// 处理个、十、百(最后3位)
const lastThree = digits.slice(-3);
// 剩余部分按每2位分组(lakh/crore 级别)
const rest = digits.slice(0, -3);
const groups = [];
// 从右向左每2位切分剩余数字
for (let i = rest.length; i > 0; i -= 2) {
groups.unshift(rest.substring(Math.max(0, i - 2), i));
}
return [...groups, lastThree].join(',');
}然而,仅格式化远远不够——若直接操作 以下为完整、生产就绪的实现方案: ✅ 关键优势说明: 立即学习“前端免费学习笔记(深入)”; ⚠️ 注意事项: 通过该方案,你将获得一个既符合印度本地习惯、又具备专业级交互体验的数字输入控件——无需依赖重型框架,纯原生 Web API 即可实现稳健交付。<input> 的 value,每次赋值都会重置光标至末尾,破坏用户体验(尤其删除时)。根本解法是改用 contenteditable="true" 的 <div>:它支持原生光标定位 API(<code>getSelection() / setSelectionRange),可精确控制编辑位置。<div
id="indian-input"
contenteditable="true"
spellcheck="false"
style="border: 1px solid #ccc; padding: 8px; min-height: 24px; font-family: monospace;"
></div>
document.addEventListener('DOMContentLoaded', () => {
const el = document.getElementById('indian-input');
// 初始化聚焦,提升可用性
el.focus();
el.addEventListener('input', function (e) {
const sel = window.getSelection();
const range = sel.getRangeAt(0);
// 计算光标前纯数字字符数量(即逻辑位置)
const beforeCursor = e.target.textContent.substring(0, range.startOffset);
const digitCountBefore = (beforeCursor.match(/\d/g) || []).length;
// 执行印度格式化(保留原始数字逻辑)
const rawDigits = e.target.textContent.replace(/[^0-9]/g, '');
const formatted = formatIndianNumber(rawDigits);
// 安全更新内容(避免触发重复 input 事件)
e.target.textContent = formatted;
// 重新定位光标:找到第 digitCountBefore 个数字后的位置
if (formatted) {
let pos = 0;
let digitSeen = 0;
for (let i = 0; i < formatted.length && digitSeen < digitCountBefore; i++) {
if (/\d/.test(formatted[i])) digitSeen++;
pos++;
}
// 设置光标到对应字符索引处(兼容逗号等分隔符)
sel.removeAllRanges();
const newRange = document.createRange();
newRange.setStart(el.firstChild, pos);
newRange.collapse(true);
sel.addRange(newRange);
}
});
// 可选:阻止非数字/逗号输入(增强数据一致性)
el.addEventListener('keydown', function (e) {
if (!/[\d,Backspace|Delete|ArrowLeft|ArrowRight|Tab|Enter]/.test(e.key) &&
!e.ctrlKey && !e.metaKey) {
e.preventDefault();
}
});
});
contenteditable 天然支持富文本光标管理,规避了 <input> 的 value 强制重写缺陷; formatIndianNumber() 函数可轻松集成货币符号(₹)、小数支持(如 1,00,000.50)或国际化配置; aria-label 和 role="textbox" 可进一步提升可访问性。
<input type="number"> 使用此方案(其原生行为与 contenteditable 冲突); div.textContent 提取纯数字(replace(/,/g, ''))作为后端字段; selectionchange 事件兼容性,建议搭配 setTimeout(..., 0) 做防抖兜底; <indian-number-input></indian-number-input>)或使用成熟库如 autoNumeric(需配置 digitGroupSeparator: ',' 和 suffixText: ' ₹' 并重写 modifyValueOnPaste)。



















