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

时间:2016-04-12 09:02:34

标签: javascript jquery

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

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

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

更新 JS小提琴: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");
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="container">
  <form class="" action="" method="post">
    <fieldset>
      <legend>Payment</legend>
      <div class="beautiful-field field-group credit-cart">
        <label class="label" for="credit-card">Credit card</label>
        <input class="field" id="credit-card" value="" autocomplete="off" type="text" />
      </div>
    </fieldset>
  </form>
</div>

7 个答案:

答案 0 :(得分:15)

仅绑定$('#credit-card').on('keypress change', function () { $(this).val(function (index, value) { return value.replace(/\W/gi, '').replace(/(.{4})/g, '$1 '); }); }); 个事件并查看。

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
// ...
Field field = null;
// retrieve the field in some way
// ...
Modifier.isPrivate(field.getModifiers())

检查here

答案 1 :(得分:5)

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

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

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

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

&#13;
&#13;
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'));
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="container">
  <form class="" action="" method="post">
    <fieldset>
      <legend>Payment</legend>
      <div class="beautiful-field field-group credit-cart">
        <label class="label" for="credit-card">Credit card</label>
        <input class="field" id="credit-card" value="" autocomplete="off" type="text" />
      </div>
    </fieldset>
  </form>
</div>
&#13;
&#13;
&#13;

答案 2 :(得分:2)

因为我不能回复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/

答案 3 :(得分:2)

2020年的答案:正确处理退格键,光标位置和美国运通卡

要处理Backspace和光标箭头,我们必须存储原始光标位置,并在除字符串末尾以外的任何位置编辑点时使用setTimeout()恢复它。

对于美国运通,我们设置partitions来处理美国运通卡(Amex)的4-6-5间距格式和所有其他卡的4-4-4-4间距。然后我们遍历它们以添加空格。

$('#credit-card').on('keyup', function () {
  $(this).val(function (index, value) {

    const selectionStart = $(this).get(0).selectionStart;
    let trimmedCardNum = value.replace(/\s+/g, '');

    if (trimmedCardNum.length > 16) {
      trimmedCardNum = trimmedCardNum.substr(0, 16);
    }

    /* Handle American Express 4-6-5 spacing format */
    const partitions = trimmedCardNum.startsWith('34') || trimmedCardNum.startsWith('37') 
                       ? [4,6,5] 
                       : [4,4,4,4];
    
    const numbers = [];
    let position = 0;
    partitions.forEach(partition => {
      const part = trimmedCardNum.substr(position, partition);
      if (part) numbers.push(part);
      position += partition;
    });

    const formattedCardNum = numbers.join(' ');

    /* Handle caret position if user edits the number later */
    if (selectionStart < formattedCardNum.length - 1) {
      setTimeout(() => {
        $(this).get(0).setSelectionRange(selectionStart, selectionStart, 'none');
      });
    };

    return formattedCardNum;
  })
});

如果您拥有自己的例程来检测美国运通卡号,请使用它。这只是检查前两位数字并与PAN/IIN standards比较。

我还发布了有关如何in an Angular application的答案。

答案 4 :(得分:0)

我通过创建自定义的on-change处理程序在Vue JS中解决了此问题。我不会在这里显示它,而是提供该解决方案的链接:Javascript: Set cursor position when changing the value of input

根据我的研究,如果您希望完全支持具有良好UX的编辑,则需要自己管理光标的位置。

pmrotule的原始JavaScript解决方案很棒,但是我的却大大简化了,因此值得研究。

答案 5 :(得分:0)

 function cc_format(value) {
var v = value.replace(/\s+/g, '').replace(/[^0-9]/gi, '')
var matches = v.match(/\d{4,16}/g);
var match = matches && matches[0] || ''
var parts = []

for (i=0, len=match.length; i<len; i+=4) {
    parts.push(match.substring(i, i+4))
}

if (parts.length) {
    return parts.join(' ')
} else {
    return value
}

}

使用

$('#input-cc-number').on('keyup',function() {      
var cc_number = cc_format($(this).val());
$('#input-cc-number').val(cc_number);

});

答案 6 :(得分:0)

$('.credit-card').keyup(function (e) {
    if (e.keyCode != 8) {
        if ($(this).val().length == 4) {
            $(this).val($(this).val() + " ");
        } else if ($(this).val().length == 9) {
            $(this).val($(this).val() + " ");
        } else if ($(this).val().length == 14) {
            $(this).val($(this).val() + " ");
        }
    }
});

这仅适用于4444 5555 2222 1111格式的卡,并且退格功能正常