代码之家  ›  专栏  ›  技术社区  ›  Scott Mitchell

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

  •  2
  • Scott Mitchell  · 技术社区  · 15 年前

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

    我想发生的是:

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

    我大部分时间都在工作,但是有一个令人头疼的问题,也就是说,如果一个用户输入的字母太快了,一些字符就空了,就好像用户在下一个文本框中出现的代码在浏览器有机会把信提交到有焦点的文本框(如果这有任何意义)之前发生了。如果你访问我的现场演示,并开始以一个像样的速度打字,你会看到一些文本框是空白的。

    我的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 检查当前文本框的X和Y值的事件处理程序 身份证件 以确定要聚焦的下一个文本框。

    怎么回事?我的直觉是当打字速度足够快时 弹起 第一次按键事件在 弹起 引发后续按键事件。

    谢谢!

    3 回复  |  直到 15 年前
        1
  •  2
  •   Alex    15 年前

    这可能是由于用户在键入时重叠按键造成的。要了解我的意思,请按住一个键,同时按下另一个键。这看起来和你说的效果一样。

    编辑:从这里看来,第二个键的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;
    }
    });
    
        2
  •  0
  •   Goyuix    15 年前

    浏览器的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);
        }
    });
    
        3
  •  0
  •   Scott Mitchell    15 年前

    想办法。。。我最终使用了jQuery的 keypress 事件加JavaScript setTimeout 功能。下面是最后一个代码,它看起来在IE 8、FF 3和Google Chrome中都能正常工作。

    $("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);
                }
            }
        });