如何实现带固定段与占位符的输入掩码,支持填充与回退恢复
输入掩码实现问题
预设条件
已声明常量:
const begin = '1234'; const end = '789';
HTML输入框预设值为 1234-56??-????-0987,需要实现输入掩码满足以下需求:
- 用户输入数字(如7)时,输入值变为
1234-567?-????-0987 - 继续输入8后,值变为
1234-5678-????-0987 - 当所有
?被替换后,停止接受输入 - 用户按退格/删除数字时,对应的
?重新显示
当前代码及问题
目前使用的代码:
const start = '123456'; const end = '0987'; const input = document.getElementById('entry-number'); input.addEventListener('input', () => { const mask = "******"; const userInput = input.value.replace(/\D/g, "").replace(start, "").replace(end, ""); const newNumber = start + userInput + mask.slice(userInput.length) + end; input.value = newNumber; });
存在两个问题:
- 不支持带连字符的掩码格式
- 按退格键会导致输入值异常
方案一:原生JavaScript实现
核心思路是保留掩码的格式结构,跟踪用户输入的数字,精准替换对应位置的?,同时处理退格/删除的回退逻辑,控制输入长度:
const input = document.getElementById('entry-number'); // 原始掩码模板,用于重置对应位置 const maskTemplate = '1234-56??-????-0987'; // 拆分模板字符,提取所有可填充的?的位置索引 const fixedChars = maskTemplate.split(''); const fillableIndices = fixedChars.map((char, idx) => char === '?' ? idx : null).filter(idx => idx !== null); const maxInputLength = fillableIndices.length; let userInputs = []; // 存储用户输入的数字 input.addEventListener('input', (e) => { const inputValue = e.target.value; // 提取所有数字字符 const rawDigits = inputValue.replace(/[^0-9]/g, ''); // 提取模板中的固定数字部分:1234560987 const fixedDigits = maskTemplate.replace(/[^0-9]/g, ''); // 过滤出用户输入的有效数字(剔除固定部分) let newUserDigits = rawDigits.replace(new RegExp(`^${fixedDigits.slice(0, 6)}|${fixedDigits.slice(6)}$`, 'g'), ''); // 限制输入长度不超过可填充位置数 newUserDigits = newUserDigits.slice(0, maxInputLength); // 更新用户输入数组 userInputs = newUserDigits.split(''); // 重新构建带格式的掩码值 const newValue = [...fixedChars]; userInputs.forEach((digit, idx) => { if (fillableIndices[idx]) { newValue[fillableIndices[idx]] = digit; } }); // 未填充的位置恢复为? for (let i = userInputs.length; i < maxInputLength; i++) { newValue[fillableIndices[i]] = '?'; } e.target.value = newValue.join(''); }); // 优化退格/删除后的光标位置 input.addEventListener('keydown', (e) => { if (e.key === 'Backspace' || e.key === 'Delete') { setTimeout(() => { const cursorPos = input.selectionStart; // 定位到光标前最近的可填充位置,避免光标跳位 const prevFillableIdx = fillableIndices.findLast(idx => idx < cursorPos); if (prevFillableIdx !== undefined) { input.setSelectionRange(prevFillableIdx + 1, prevFillableIdx + 1); } }, 0); } }); // 初始化输入框值 input.value = maskTemplate;
方案二:使用jQuery-Mask插件实现
如果项目已引入jQuery,可借助jQuery-Mask插件简化实现,自定义掩码规则即可:
<input type="text" id="entry-number" value="1234-56??-????-0987"> <script src="jquery.min.js"></script> <script src="jquery.mask.min.js"></script> <script> $(document).ready(function() { const maskPattern = '1234-56AA-AAAA-0987'; $('#entry-number').mask(maskPattern, { translation: { 'A': { pattern: /[0-9]/, fallback: '?' } }, maxlength: false, onKeyPress: function(cep, e, field, options) { // 计算已填充的数字数量 const filledCount = cep.replace(/[^0-9]/g, '').replace(/1234560987/g, '').length; const totalFillable = maskPattern.match(/A/g).length; // 填满所有位置后阻止继续输入 if (filledCount >= totalFillable) { e.preventDefault(); } } }); }); </script>
内容的提问来源于stack exchange,提问作者LessStress
相关产品推荐
相关产品推荐

