如果键入太快,关注下一个元素的Keyup事件处理程序将丢失刚输入的字符

时间:2010-11-24 00:02:11

标签: jquery

我有一个网页,其中16个文本框排列在4x4网格中。这个想法是用户将在每个文本框中精确键入一个字符(特别是一个字母)。您可以在http://fuzzylogicinc.net/Boggle/EnterBoardClientSide.aspx

在线查看此页面

我想要发生的事情如下:

  • 当页面加载时,左上角的文本框被聚焦
  • 在文本框中键入字母应输入该字母,然后自动将焦点设置为网格中的下一个文本框
  • 如果用户选择文本框(通过鼠标或通过Shift-Tabbing返回到上一个文本框),则应选择文本框中的条目,以便他们只需键入新字母即可覆盖旧字母。

我在大多数情况下都有这个工作,但有一个棘手的问题 - 也就是说,如果用户输入的字母太快,一些文本框会留空,就好像将用户带到下一个文本框的代码一样在浏览器有机会将字母实际提交到具有焦点的文本框之前(如果这有意义)。如果您访问我的现场演示并开始以合适的价格打字,您会看到一些文本框留空。

我的JavaScript,可以看作是整个here,它有以下代码用于选择/聚焦/移动到下一个文本框:

$("input.BoggleGridCell")
    .focus(function () {
        $(this).select();
    })
    .keyup(function (event) {
        var code = (event.keyCode ? event.keyCode : event.which);

        if ((code >= 65 && code <= 90) || (code >= 97 && code <= 122)) {
            var currentId = $(this).attr('id');

            var leftDigit = currentId.substring(1, 2);
            var rightDigit = currentId.substring(2, 3);
            if (leftDigit != 3 || rightDigit != 3) {
                if (rightDigit == 3) {
                    rightDigit = 0;
                    leftDigit++;
                }
                else {
                    rightDigit++;
                }

                var moveToId = 'c' + leftDigit + rightDigit;
                var newCell = document.getElementById(moveToId);
                if (newCell)
                    newCell.focus();
            }
            else {
                $("#solve").focus();
            }
        }
    });

请注意,网格中的所有文本框都有一个CSS类BoggleGridCell。网格中的每个文本框都有一个id形式cXY,其中X是行号,Y是列号。我在keyup事件处理程序中有一些代码,用于检查当前文本框id的此X和Y值,以确定要关注的下一个文本框。

这里发生了什么?我的直觉是,当以足够的速度打字时,第一次按键的keyup事件在提出后续按键的keyup事件时尚未完成。

谢谢!

3 个答案:

答案 0 :(得分:2)

可能是问题是由用户在键入时重叠按键引起的。要查看我的意思,请按住一个键,然后同时按另一个键。这似乎与你所说的效果相同。

编辑:从这看起来似乎第二个键的keyUp事件触发,然后第一个键的keyUp事件触发。但是,中断的顺序会阻止第二次按键的字母插入到适当的输入中。

你可以通过添加keyDown事件来解决这个问题,首先检查当前没有关键字。

var pressed=0;
$("input.BoggleGridCell")

.focus(function () {

  $(this).select();

})
.keydown(function(event){
  var code = (event.keyCode ? event.keyCode : event.which);
  if ((code >= 65 && code <= 90) || (code >= 97 && code <= 122)) {
    pressed=code;
  }
})      
.keyup(function (event) {
  if(pressed!=0){
    var code = (event.keyCode ? event.keyCode : event.which);
    if ((code >= 65 && code <= 90) || (code >= 97 && code <= 122)) {
     //Your Code Here
    }
  }
  pressed=0;
}
});

答案 1 :(得分:0)

浏览器DOM和事件在一致且可预测的性能方面非常糟糕 - 特别是在处理键盘或鼠标事件时。我的建议是在某种程度上重新构建这个想法......否则你最终会长期追逐这样的问题。

看了你的演示后,我不太清楚要推荐什么。有一个处理输入的文本框(它甚至可以是不可见/隐藏的),只是从那里调度事件 - 可能挂钩'更改'事件而不是单个按键可能会更可靠,尽管它可能也是如此与你想要做的事情大相径庭。它肯定会增加额外的复杂性,允许编辑单个单元格(挂钩模糊事件)。

我的另一个想法是让keyup事件尽快返回 - 将主体的大部分包装成一个匿名函数,该函数被传递给setTimeOut()调用。提前预先计算下一个单元格可能是有益的,因此您可以跳过所有逻辑。我不知道这会解决性能问题但是...警告我没有测试这个代码 - 我把它作为一个想法。围绕$(this)调用的闭包可能存在问题。

$("input.BoggleGridCell")
.focus(function () {
    $(this).select();
})
.keyup(function (event) {
    var code = (event.keyCode ? event.keyCode : event.which);
    if ((code >= 65 && code <= 90) || (code >= 97 && code <= 122)) {
        setTimeOut(function(){
          var currentId = $(this).attr('id');
          var leftDigit = currentId.substring(1, 2);
          var rightDigit = currentId.substring(2, 3);
          if (leftDigit != 3 || rightDigit != 3) {
              if (rightDigit == 3) {
                  rightDigit = 0;
                  leftDigit++;
              } else {
                rightDigit++;
              }
              var moveToId = 'c' + leftDigit + rightDigit;
              var newCell = document.getElementById(moveToId);
              if (newCell)
                newCell.focus();
          } else {
            $("#solve").focus();
        }, 1);
    }
});

答案 2 :(得分:0)

想出一个解决方法......我最终使用了jQuery的keypress事件加上JavaScript的setTimeout函数。这是IE 8,FF 3和谷歌浏览器中预期的最终代码。

$("input.BoggleGridCell")
    .focus(function () {
        $(this).select();
    })
    .keypress(function (event) {
        var code = (event.keyCode ? event.keyCode : event.which);

        if ((code >= 65 && code <= 90) || (code >= 97 && code <= 122)) {
            var currentId = $(this).attr('id');

            var leftDigit = currentId.substring(1, 2);
            var rightDigit = currentId.substring(2, 3);
            if (leftDigit != 3 || rightDigit != 3) {
                if (rightDigit == 3) {
                    rightDigit = 0;
                    leftDigit++;
                }
                else {
                    rightDigit++;
                }

                setTimeout(function () {
                    var moveToId = 'c' + leftDigit + rightDigit;
                    var newCell = document.getElementById(moveToId);
                    if (newCell)
                        newCell.focus();
                }, 1);
            }
            else {
                setTimeout('$("#solve").focus();', 1);
            }
        }
    });