Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/422.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 听多个按键_Javascript_Keydown_Addeventlistener - Fatal编程技术网

Javascript 听多个按键

Javascript 听多个按键,javascript,keydown,addeventlistener,Javascript,Keydown,Addeventlistener,我试图让用户使用箭头键移动页面上的元素。到目前为止,我的移动功能适用于上/下/左/右,但不适用于对角线(同时按下两个箭头键) 我的听众是这样的: addEventListener('keydown', function(e){ move = false; x = false; y = false; var keycode; if (window.event) keycode = window.event.keyCode; else if (e) k

我试图让用户使用箭头键移动页面上的元素。到目前为止,我的移动功能适用于上/下/左/右,但不适用于对角线(同时按下两个箭头键)

我的听众是这样的:

addEventListener('keydown', function(e){
    move = false;
    x = false;
    y = false;
    var keycode;
    if (window.event) keycode = window.event.keyCode;
    else if (e) keycode = e.which;
    switch(keycode){
        case 37:
            move = true;
            x = 'negative';
            //prevent page scroll
            e.preventDefault()
        break;
        case 38:
            move = true;
            y = 'negative'
            //prevent page scroll
            e.preventDefault()
        break;
        case 39:
            move = true;
            x = 'positive'
            //prevent page scroll
            e.preventDefault()
        break;
        case 40:
            move = true;
            y = 'positive'
            //prevent page scroll
            e.preventDefault()
        break;
    }
    if(move){
        animation.move(x,y);
    }
    return false;
})
其想法是,如果用户按下箭头键,它会将
x
y
设置为
,并触发move()函数,该函数将在所需方向上移动元素预设数量的像素,如果按下两个键,则会触发第二个事件。。。我也希望能够让用户通过快速释放和按下键来轻松改变方向,但这两种情况都不会发生,但是,如果用户按下另一个方向键,他们似乎需要等待一段时间才能移动,除非他们完全释放键,然后按下另一个方向键,在第一个键被释放之前,它根本不会响应第二个键。

小提琴:

创建一个临时缓存以记住您的按键笔划

处理两个键的实现将遵循以下模式:


    • 清除以前的超时
    • 检查a键代码是否已缓存。
      如果是,以及有效组合:
      -
      删除所有缓存的密钥代码
      -
      执行此组合的功能
      否则
      -
      删除所有缓存的密钥代码
      -
      存储新的密钥代码
      -
      设置一个超时,以合理的延迟清除按键代码(见下文)
  • 重复1次
  • 一个合理的延迟:尝试知道哪一个超时对你来说是足够的。当延迟太短时,下一个启动的事件将找不到以前输入的钥匙代码

    延迟太长时,当您不需要时,按键笔划将堆叠。

    代码 我已经创建了一个高效的函数,将您的代码牢记在心。您应该能够很容易地实现它

    (function(){ //Anonymous function, no leaks
        /* Change the next variable if necessary */
        var timeout = 200; /* Timeout in milliseconds*/
    
        var lastKeyCode = -1;
        var timer = null;
        function keyCheck(ev){
            var keyCode = typeof ev.which != "undefined" ? ev.which : event.keyCode;
            /* An alternative way to check keyCodes:
             * if(keyCode >= 37 && keyCode <= 40) ..*/
             /*37=Left  38=Up  39=Right  40=Down */
            if([37, 38, 39, 40].indexOf(keyCode) != -1){
    
                /* lastKeyCode == -1 = no saved key
                   Difference betwene keyCodes == opposite keys = no possible combi*/
                if(lastKeyCode == -1 || Math.abs(lastKeyCode - keyCode) == 2){
                    refresh();
                    lastKeyCode = keyCode;
                } else if(lastKeyCode == keyCode){
                    clear([lastKeyCode]);
                } else {
                    /* lastKeyCode != -1 && keyCode != lastKeyCode
                       and no opposite key = possible combi*/
                    clear([lastKeyCode, keyCode]);
                    lastKeyCode = -1
                }
                ev.preventDefault(); //Stop default behaviour
                ev.stopPropagation(); //Other event listeners won't get the event
            }
    
            /* Functions used above, grouped together for code readability */
            function reset(){
                keyCombi([lastKeyCode]);
                lastKeyCode = -1;
            }
            function clear(array_keys){
                clearTimeout(timer);
                keyCombi(array_keys);
            }
            function refresh(){
                clearTimeout(timer);
                timer = setTimeout(reset, timeout);
            }
        }
    
        var lastX = false;
        var lastY = false;
        function keyCombi(/*Array*/ keys){
            /* Are the following keyCodes in array "keys"?*/
            var left = keys.indexOf(37) != -1;
            var up = keys.indexOf(38) != -1;
            var right = keys.indexOf(39) != -1;
            var down = keys.indexOf(40) != -1;
    
            /* What direction? */
            var x = left ? "negative" : right ? "positive" : false;
            var y = up ? "negative" : down ? "positive" : false;
            /* Are we heading to a different direction?*/
            if(lastX != x || lastY != y) animation.move(x, y);
            lastX = x;
            lastY = y;
        }
    
        //Add event listener
        var eventType = "keydown";window["on"+eventType] = keyCheck;
    })();
    
    (function(){//匿名函数,无泄漏
    /*如有必要,请更改下一个变量*/
    var timeout=200;/*以毫秒为单位的超时*/
    var lastKeyCode=-1;
    var定时器=null;
    功能键检查(ev){
    var keyCode=ev.WHITH的类型!=“未定义”?ev.WHITH:event.keyCode;
    /*检查钥匙代码的另一种方法:
    
    *如果(keyCode>=37&&keyCode从逻辑上讲,这听起来相当简单:

  • 第一个键触发一个键关闭事件,将此事件存储在堆栈中
  • 然后第二个键触发一个键关闭事件,将该事件存储在堆栈中
  • 现在有两个向下键,没有向上键
  • 如果钥匙打开,你有三种可能性
  • 您只有一个事件=>朝那个方向走
  • 您有两个事件=>沿对角线进行
  • 您有两个以上的事件,或一个无效选项(例如,右和左)=>什么都不做,或您想做的任何事情
  • 清除堆栈
  • 这是您的代码,稍作修改…它很有效。将元素移到父元素上


    Rob W是对的,你应该有一个在一段时间内按下按键的动态缓存。但是为什么呢?如果你在做一个动态游戏,那么必须有更高的抽象性。总的来说,如果你想做这样的事情,你需要提高你的编码水平。(或者这只会让你头疼。)

    我很好奇你说我应该删除缓存的密钥代码。我想我主要是想在
    keyup
    事件中这样做?还是只要密钥保持不变,keydown事件就会持续触发?@ChrisSobolewski我已经更新了我的答案。还可以查看Fiddle链接以获得一个实例。哇,谢谢!这很相似到了我要去的地方…你肯定超越了我,先生。