Javascript信用卡字段 – 每四个字符添加空格 – Backspace无法正常工作

我有一个信用卡字段,我想在用户输入其信用卡号时处理。 假设用户可以输入数字和字母字符,并且每四个字符必须添加一个空格。 输入部分工作正常,但我有退格问题。 如果我将光标放在数字上,则使用退格键删除有效,但当光标位于某个空格时,它无法正常工作:在这种情况下,用户必须按住退格键才能正确删除某些输入。

另一个要求是让剪贴板操作(复制,剪切,粘贴)在该字段上正常工作。

我不能使用任何插件的解决方案(如JQuery Mask插件),如果可能的话我不会直接使用keyCode。

更新了 JS Fiddle: https : //jsfiddle.net/ot2t9zr4/10/

片段

$('#credit-card').on('keypress change blur', function () { $(this).val(function (index, value) { return value.replace(/[^a-z0-9]+/gi, '').replace(/(.{4})/g, '$1 '); }); }); $('#credit-card').on('copy cut paste', function () { setTimeout(function () { $('#credit-card').trigger("change"); }); }); 
  
Payment

仅绑定keypress事件并查看。

 $('#credit-card').on('keypress change', function () { $(this).val(function (index, value) { return value.replace(/\W/gi, '').replace(/(.{4})/g, '$1 '); }); }); 

点击这里

史蒂夫戴维斯已经指出了它,但是如果你只用replace()重新格式化整个值,则插入位置将始终位于输入值的末尾,如果用户编辑他之前输入的内容,这可能会令人讨厌。 如果插入位置位于其他地方或者已经进行了选择以便用新数字替换它将导致糟糕的用户体验。

话虽这么说,摆脱这种行为的一个好方法是创建一个自定义替换函数,其中for循环遍历每个字符,然后您将能够知道插入的空间是否在当前插入位置之前并更新如果是这样的话。

纯JavaScript解决方案: https : //jsfiddle.net/pmrotule/217u7fru/ 。

编辑 :我添加了对美国运通格式的支持(15位而不是16位)。

 input_credit_card = function(jQinp) { var format_and_pos = function(input, char, backspace) { var start = 0; var end = 0; var pos = 0; var value = input.value; if (char !== false) { start = input.selectionStart; end = input.selectionEnd; if (backspace && start > 0) // handle backspace onkeydown { start--; if (value[start] == " ") { start--; } } // To be able to replace the selection if there is one value = value.substring(0, start) + char + value.substring(end); pos = start + char.length; // caret position } var d = 0; // digit count var dd = 0; // total var gi = 0; // group index var newV = ""; var groups = /^\D*3[47]/.test(value) ? // check for American Express [4, 6, 5] : [4, 4, 4, 4]; for (var i = 0; i < value.length; i++) { if (/\D/.test(value[i])) { if (start > i) { pos--; } } else { if (d === groups[gi]) { newV += " "; d = 0; gi++; if (start >= i) { pos++; } } newV += value[i]; d++; dd++; } if (d === groups[gi] && groups.length === gi + 1) // max length { break; } } input.value = newV; if (char !== false) { input.setSelectionRange(pos, pos); } }; jQinp.keypress(function(e) { var code = e.charCode || e.keyCode || e.which; // Check for tab and arrow keys (needed in Firefox) if (code !== 9 && (code < 37 || code > 40) && // and CTRL+C / CTRL+V !(e.ctrlKey && (code === 99 || code === 118))) { e.preventDefault(); var char = String.fromCharCode(code); // if the character is non-digit // -> return false (the character is not inserted) if (/\D/.test(char)) { return false; } format_and_pos(this, char); } }). keydown(function(e) // backspace doesn't fire the keypress event { if (e.keyCode === 8 || e.keyCode === 46) // backspace or delete { e.preventDefault(); format_and_pos(this, '', this.selectionStart === this.selectionEnd); } }). on('paste', function() { // A timeout is needed to get the new value pasted setTimeout(function() { format_and_pos(jQinp[0], ''); }, 50); }). blur(function() // reformat onblur just in case (optional) { format_and_pos(this, false); }); }; input_credit_card($('#credit-card')); 
  
Payment

因为我不能回复Developer107的评论; 如果您只想要数字(使用正则表达式并且不想在字段上指定它。您可以这样做:

 $('#credit-card').on('keypress change', function () { $(this).val(function (index, value) { return value.replace(/[^0-9]/g, "").replace(/\W/gi, '').replace(/(.{4})/g, '$1 '); }); }); 

https://jsfiddle.net/ot2t9zr4/4/

您的核心问题是,当使用JavaScript更新输入字段的值时,光标/选择位置将设置为字符串的结尾。

当用户输入附加到最后时,这很好,但是如果删除或在中间插入数字,这会变得非常烦人,正如您所观察到的那样。 解决此问题的一种方法是在每次编辑之前和之后保存和恢复字段内的光标位置。

粗暴地完成:

 $('#credit-card').on('keyup keypress change', function () { var s = this.selectionStart, e = this.selectionEnd; var oldleft = $(this).val().substr(0,s).replace(/[^ ]/g, '').length; $(this).val(function (index, value) { return value.replace(/\W/gi, '').replace(/(.{4})/g, '$1 '); }); var newleft = $(this).val().substr(0,s).replace(/[^ ]/g, '').length; s += newleft - oldleft; e += newleft - oldleft; this.setSelectionRange(s, e); }); 

这不是一个完整的解决方案,因为如果您的代码插入/删除导致这些位置被移动的字符,则需要更新se位置。

如果不需要更新,也可以通过不设置val()显着优化这一点。