keyup 事件处理程序更改焦点不适用于快速键入
keyup event handler changes focus not working for quick typing
我想要一个 PIN 输入表单,其中每个字符都输入到单独的 html 输入中。
我正在尝试捕获 javascript 中的 keyup 事件,以便我可以将焦点转移到下一个输入元素,从而使用户无需通过单击鼠标或 Tab 键自行更改它。
除非用户输入的速度非常快,否则它可以正常工作。例如,如果用户非常快地键入字符“1”和“2”,我发现第一个输入现在正确地包含字符“1”,而第二个输入仍然是空的,并且焦点已移至第三个输入。
为什么?
代码如下:
$(document).ready(function () {
$('.pinchar').keyup(function (e) {
if (
(e.which == 8) //backspace
|| (e.which == 46) // del
|| (e.which == 9) // tab
|| (e.which == 13) // return
|| (e.which == 27) // esc
|| (e.which == 37) // arrow
|| (e.which == 38) // arrow
|| (e.which == 39) // arrow
|| (e.which == 40) // arrow
|| (e.which == 27) // esc
|| (e.which == 20) // CAPS LOCK
|| (e.which == 17) // Ctrl
|| (e.which == 18) // Alt
|| (e.which == 16)) { //shift
return false;
} else {
$(this).parent().next().find('.pinchar').focus();
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="enterPINTable">
<tr>
<td>
<input name="txtPIN1" id="txtPIN1" class="pinchar" size="1">
</td>
<td>
<input name="txtPIN2" id="txtPIN2" class="pinchar" size="1">
</td>
<td>
<input name="txtPIN3" id="txtPIN3" class="pinchar" size="1">
</td>
<td>
<input name="txtPIN4" id="txtPIN4" class="pinchar" size="1">
</td>
</tr>
</table>
keyup
按下一个键会失败,然后在松开之前再按另一个键。事件的顺序是 keydown 1
、keydown 2
、keyup 1
、keydown 2
。但是,由于字符是在 keydown
(和 keypress
)之后生成的,在这种情况下,在第一个 keyup
事件之前,input
中已经有两个字符。
改为尝试 input
事件:
$('.pinchar').on('input', function (e) {
// ... etc.
任何变化都会立即触发。
但要正确处理其他键,您还需要捕获 keydown
事件(对于箭头键和退格键)。
我会建议这个代码:
$(document).ready(function () {
var $inputs = $(".enterPINTable .pinchar");
function step(inp, dir, clr) {
if (clr) $(inp).val("");
var buffer = $(inp).val(); // get excess characters
// spread characters in next boxes to ensure max 1 char
var curr = $inputs.index(inp);
for (var i = curr, j = 0; j < buffer.length && i < $inputs.length; i++, j++) {
$inputs.eq(i).val(buffer[j]);
}
if (dir < 0) curr-= curr > 0;
else curr = Math.min(curr + (j||dir), $inputs.length-1);
var $next = $inputs.eq(curr);
$next.focus();
setTimeout(function () {
$next.select();
}, 0);
return false;
}
$inputs.on("focus", function () {
$(this).select(); // always select the "whole" (1 char) text
}).on("mouseup", function () { // Attempt to unselect?
setTimeout(function () { // Keep character selected....
$(this).select();
}.bind(this));
}).on("keydown", function (e) {
if (e.key == "ArrowLeft" || e.key == "ArrowUp") return step(this, -1);
if (e.key == "ArrowRight" || e.key == "ArrowDown") return step(this, 1);
if (e.key == "Backspace") return step(this, -1, 1);
}).on("input", function (e) {
step(this, 0);
}).eq(0).focus();
});
.pinchar { width: 1em; text-align: center }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="enterPINTable">
<tr>
<td>
<input name="txtPIN1" id="txtPIN1" class="pinchar">
</td>
<td>
<input name="txtPIN2" id="txtPIN2" class="pinchar">
</td>
<td>
<input name="txtPIN3" id="txtPIN3" class="pinchar">
</td>
<td>
<input name="txtPIN4" id="txtPIN4" class="pinchar">
</td>
</tr>
</table>
上面的代码旨在始终 select 当前字符,这样如果您键入另一个字符,它就会替换当前字符。如果您成功删除 selection(不容易)并尝试添加第二个字符,它将在下一个框中结束。从剪贴板粘贴一系列字符也会导致每个输入框一个字符的传播。
left
、right
、tab
、shift
+tab
、backspace
和 delete
键作为可以预料。
使用 CSS 调整输入的大小,并使文本居中,似乎可以提供更好的结果。
Keypress 更适合这种情况。
问题是 keyup 触发晚了,即在 keydown 和 keypress 之后。
顺序是这样的:
当按下键时,立即触发 keydown 事件。在那种情况下,该值不会打印在屏幕上。触发该按键后,此时将打印该值。
在这两个事件之后,当您将手指从键上抬起时,将触发 keyup。
因此,当您快速按下两个键时,会快速连续调用它们的按键(当值打印在屏幕上时),因此值会打印在同一输入上,然后调用两个键的 keyup 将焦点转发到下一个输入的下一个(将它们留空,因为在按键期间已经打印了值)。
$(document).ready(function () {
$('.pinchar').keypress(function (e) {
$(this).parent().next().find('.pinchar').focus();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="enterPINTable">
<tr>
<td>
<input name="txtPIN1" id="txtPIN1" class="pinchar" size="1">
</td>
<td>
<input name="txtPIN2" id="txtPIN2" class="pinchar" size="1">
</td>
<td>
<input name="txtPIN3" id="txtPIN3" class="pinchar" size="1">
</td>
<td>
<input name="txtPIN4" id="txtPIN4" class="pinchar" size="1">
</td>
</tr>
</table>
我想要一个 PIN 输入表单,其中每个字符都输入到单独的 html 输入中。
我正在尝试捕获 javascript 中的 keyup 事件,以便我可以将焦点转移到下一个输入元素,从而使用户无需通过单击鼠标或 Tab 键自行更改它。
除非用户输入的速度非常快,否则它可以正常工作。例如,如果用户非常快地键入字符“1”和“2”,我发现第一个输入现在正确地包含字符“1”,而第二个输入仍然是空的,并且焦点已移至第三个输入。
为什么?
代码如下:
$(document).ready(function () {
$('.pinchar').keyup(function (e) {
if (
(e.which == 8) //backspace
|| (e.which == 46) // del
|| (e.which == 9) // tab
|| (e.which == 13) // return
|| (e.which == 27) // esc
|| (e.which == 37) // arrow
|| (e.which == 38) // arrow
|| (e.which == 39) // arrow
|| (e.which == 40) // arrow
|| (e.which == 27) // esc
|| (e.which == 20) // CAPS LOCK
|| (e.which == 17) // Ctrl
|| (e.which == 18) // Alt
|| (e.which == 16)) { //shift
return false;
} else {
$(this).parent().next().find('.pinchar').focus();
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="enterPINTable">
<tr>
<td>
<input name="txtPIN1" id="txtPIN1" class="pinchar" size="1">
</td>
<td>
<input name="txtPIN2" id="txtPIN2" class="pinchar" size="1">
</td>
<td>
<input name="txtPIN3" id="txtPIN3" class="pinchar" size="1">
</td>
<td>
<input name="txtPIN4" id="txtPIN4" class="pinchar" size="1">
</td>
</tr>
</table>
keyup
按下一个键会失败,然后在松开之前再按另一个键。事件的顺序是 keydown 1
、keydown 2
、keyup 1
、keydown 2
。但是,由于字符是在 keydown
(和 keypress
)之后生成的,在这种情况下,在第一个 keyup
事件之前,input
中已经有两个字符。
改为尝试 input
事件:
$('.pinchar').on('input', function (e) {
// ... etc.
任何变化都会立即触发。
但要正确处理其他键,您还需要捕获 keydown
事件(对于箭头键和退格键)。
我会建议这个代码:
$(document).ready(function () {
var $inputs = $(".enterPINTable .pinchar");
function step(inp, dir, clr) {
if (clr) $(inp).val("");
var buffer = $(inp).val(); // get excess characters
// spread characters in next boxes to ensure max 1 char
var curr = $inputs.index(inp);
for (var i = curr, j = 0; j < buffer.length && i < $inputs.length; i++, j++) {
$inputs.eq(i).val(buffer[j]);
}
if (dir < 0) curr-= curr > 0;
else curr = Math.min(curr + (j||dir), $inputs.length-1);
var $next = $inputs.eq(curr);
$next.focus();
setTimeout(function () {
$next.select();
}, 0);
return false;
}
$inputs.on("focus", function () {
$(this).select(); // always select the "whole" (1 char) text
}).on("mouseup", function () { // Attempt to unselect?
setTimeout(function () { // Keep character selected....
$(this).select();
}.bind(this));
}).on("keydown", function (e) {
if (e.key == "ArrowLeft" || e.key == "ArrowUp") return step(this, -1);
if (e.key == "ArrowRight" || e.key == "ArrowDown") return step(this, 1);
if (e.key == "Backspace") return step(this, -1, 1);
}).on("input", function (e) {
step(this, 0);
}).eq(0).focus();
});
.pinchar { width: 1em; text-align: center }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="enterPINTable">
<tr>
<td>
<input name="txtPIN1" id="txtPIN1" class="pinchar">
</td>
<td>
<input name="txtPIN2" id="txtPIN2" class="pinchar">
</td>
<td>
<input name="txtPIN3" id="txtPIN3" class="pinchar">
</td>
<td>
<input name="txtPIN4" id="txtPIN4" class="pinchar">
</td>
</tr>
</table>
上面的代码旨在始终 select 当前字符,这样如果您键入另一个字符,它就会替换当前字符。如果您成功删除 selection(不容易)并尝试添加第二个字符,它将在下一个框中结束。从剪贴板粘贴一系列字符也会导致每个输入框一个字符的传播。
left
、right
、tab
、shift
+tab
、backspace
和 delete
键作为可以预料。
使用 CSS 调整输入的大小,并使文本居中,似乎可以提供更好的结果。
Keypress 更适合这种情况。
问题是 keyup 触发晚了,即在 keydown 和 keypress 之后。
顺序是这样的:
当按下键时,立即触发 keydown 事件。在那种情况下,该值不会打印在屏幕上。触发该按键后,此时将打印该值。
在这两个事件之后,当您将手指从键上抬起时,将触发 keyup。
因此,当您快速按下两个键时,会快速连续调用它们的按键(当值打印在屏幕上时),因此值会打印在同一输入上,然后调用两个键的 keyup 将焦点转发到下一个输入的下一个(将它们留空,因为在按键期间已经打印了值)。
$(document).ready(function () {
$('.pinchar').keypress(function (e) {
$(this).parent().next().find('.pinchar').focus();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="enterPINTable">
<tr>
<td>
<input name="txtPIN1" id="txtPIN1" class="pinchar" size="1">
</td>
<td>
<input name="txtPIN2" id="txtPIN2" class="pinchar" size="1">
</td>
<td>
<input name="txtPIN3" id="txtPIN3" class="pinchar" size="1">
</td>
<td>
<input name="txtPIN4" id="txtPIN4" class="pinchar" size="1">
</td>
</tr>
</table>