KeyUp和KeyDown事件,如果用户输入太快

6
我不知道如何解决这个问题:
用户可以在输入框中开始输入一些数字。在输入数字后,光标将移动到下一个输入框。但是,如果用户输入太快,也就是说,在两个数字之间没有按键松开的时间,它将无法正常工作。
因此,如果用户输入“12”而不是“1”和“2”,则第一个输入框应该有值“1”,第二个输入框应该有值“2”,并且焦点应该设置为第三个输入框。
<form>
    <input type="password" maxlength="1" name="pin1" autofocus />
    <input type="password" maxlength="1" name="pin2" />
    <input type="password" maxlength="1" name="pin3" />
    <input type="password" maxlength="1" name="pin4" />
</form>

$('form input').on('keydown', function(event) {        
    if (event.shiftKey || event.which <= 47 || event.which >= 58)
        return false;

}).on('keyup', function (event) {
    if (event.currentTarget.value.length >= 1)
        $(event.currentTarget).next('input').focus();
});

http://jsfiddle.net/bbeg17r8/


2
为什么不用一个输入框来输入四位数?是因为你显示数字的方式吗?如果是这样,也许你应该以另一种方式解决这个问题,或者做出妥协,而不是冒着降低用户体验的风险。 - GolezTrol
1
首先,您应该使用keypress事件,而不是keydown。根据键盘类型,keydown可能会返回意外行为,因此不应用于“字符”检查。 - A. Wolff
你需要支持旧版浏览器(例如IE8)吗? - A. Wolff
4个回答

4

您尝试过使用input事件结合这两个条件吗?这将适用于多个用户操作,如键盘事件剪切/粘贴事件等:

$('form input').on('input keypress', function(event) {     
    if (event.type == "keypress" && (event.shiftKey || event.which <= 47 || event.which >= 58))
        return false;


    if (event.currentTarget.value.length >= 1)
        $(event.currentTarget).next('input').focus();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
    <input type="password" maxlength="1" name="pin1" autofocus />
    <input type="password" maxlength="1" name="pin2" />
    <input type="password" maxlength="1" name="pin3" />
    <input type="password" maxlength="1" name="pin4" />
</form>


但是这会让用户输入所有字符。我需要仅允许数字值。 - user3142695
"input"事件不是键盘事件,它不处理"event.which"、"event.shiftKey"等。 - A. Wolff
啊!正如A.Wolff所指出的,你可以再添加一个keypress事件。@user3142695 - Jai
关于这个问题的最后一个问题是:在键入一个值之后,我确实可以进入下一个输入。一切都正常运行。但是如果我按下“退格”键,我想去到上一个输入并删除其内容:if (event.type == "keypress" && event.which === 8) $(event.currentTarget).prev('input').focus();但这个方法不起作用。 - user3142695
如果(event.type == "keypress") console.log(event.which);在我按退格键时不会给我一个值。但是对于每个字符,我都能得到值...我不明白这是为什么。 - user3142695
显示剩余2条评论

3
您需要更为复杂的技能来处理这种情况,特别是如果用户使用粘贴方式输入他们的PIN码(虽然他们不应该这样做,但实际上会这样做)。
我会删除maxlength并在输入时将文本分布到不同的输入框中。使用keypress事件可以很好地处理实际的文本按键输入,当然我们还需要changeinput事件。
以下是一个粗略的版本:
$('input').on('keypress input change', function(event) {
    setTimeout(handleInputs, 0);
});
function handleInputs() {
  var focussed = false;
  var inputs = $("input").get();

  // Collect the values
  var text = inputs.reduce(
    function(acc, input) {
      return acc + input.value;
    },
    ""
  );

  // ...adjust `text` here if you want...

  // Distribute the values
  inputs.forEach(function(input, index) {
    input.value = text.charAt(index);
    if (!focussed && !input.value) {
      console.log("Focussing " + this.name);
      input.focus();
      focussed = true;
    }
  });
}

实时示例:

$('input').on('keypress input change', function(event) {
 setTimeout(handleInputs, 0);
});
function handleInputs() {
  var focussed = false;
 var inputs = $("input").get();
 var text = inputs.reduce(
    function(acc, input) {
      return acc + input.value;
    },
    ""
  );
  inputs.forEach(function(input, index) {
    input.value = text.charAt(index);
    if (!focussed && !input.value) {
    console.log("Focussing " + this.name);
     input.focus();
      focussed = true;
    }
  });
}
<form>
  <input type="password" name="pin1" autofocus />
  <input type="password" name="pin2" />
  <input type="password" name="pin3" />
  <input type="password" name="pin4" />
</form>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>


如果已经使用了“input”事件,那么“change”和“keypress”事件在这里不是多余的吗?而且,在这里,它并不仅处理数字值,对吧? - A. Wolff
@A.Wolff:我对不支持“input”功能的旧浏览器有点过于担心了。 :-) - T.J. Crowder
所以,如果我没错的话,你应该添加paste事件和可能的mouseup事件(用于拖动)。 - A. Wolff
1
你为什么要使用 setTimeout - user3142695
1
keypress事件中,新字符尚未添加到输入中,因此我们需要让事件完成,然后读取输入值。 - T.J. Crowder
显示剩余4条评论

1
你可以在 keydown 事件上触发时添加你已经有的代码。
$('input').on('keydown', function(event) {   
    if (event.shiftKey || event.which <= 47 || event.which >= 58) {
        return false;
    }
    if (event.currentTarget.value.length >= 1) {
        $(event.currentTarget).next('input').focus();
    }
});

http://jsfiddle.net/bbeg17r8/2/


不错。但如果我输入“12”,焦点应该在第三个输入字段后面。 - user3142695

0

这是你可以用来处理所有(我能想到的)情况的方法:

$("input").on('change keyup paste', function(event) {
  if(event.which === 9) return; // tab pressed, keep default behaviour
  var char = this.value.slice(0, 1);
  if (!/\d/.test(char)) this.value = "";
  else $(this).next('input').focus();
});

-jsFiddle-

(使用文本类型的输入使其更清晰)

附注:我厌倦了 jsFiddle 不能正确更新的问题。自从 jsFiddle 进行了最新的主要更新以来,这个问题真的让我很困扰...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接