禁用箭头键在用户与<canvas>交互时滚动

3
我已经在JS中添加了一个事件监听器来监听keyup/keydown事件,我试图在HTML画布上移动一个精灵。我大部分工作都做好了,但是当用户按下箭头键时,页面被滚动。
我正在返回false,但这似乎不起作用。此外,我的理解是以这种方式返回false会禁用整个页面的箭头按钮滚动。我希望仅在用户与画布本身交互时禁用它。
以下是我的事件监听器:
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';
        break;
        case 38:
            move = true;
            y = 'negative'
        break;
        case 39:
            move = true;
            x = 'positive'
        break;
        case 40:
            move = true;
            y = 'positive'
        break;
    }
    if(move){
        animation.move(x,y);
    }
    return false;
})

编辑:

下面的答案有一个好主意,可以确保画布聚焦,但是我仍然困惑为什么在我的EventListener函数中返回false并没有禁用滚动。

3个回答

11
只要你以某种方式为画布设置焦点(即canvas.tabIndex = 1;),然后在return false之前添加e.preventDefault(),它就可以工作。
例子: http://jsfiddle.net/faAkN/

谢谢。对我有用! - ncmathsadist

1

我曾经遇到过类似的问题,并想出了一个解决方案。

以下是我的解决方案:

function $(){
  return document.querySelector.apply(document,arguments);
}
var canvas = $('canvas'),
    keysDown = []; // You can also define this as an object, {}
canvas.tabIndex = 0;
canvas.onclick = function(e){
  document.body.scrollTop = canvas.offsetTop; // scrolls to canvas element
  canvas.focus(); // re-focuses canvas in case the scroll unfocused it
}
canvas.onkeydown = canvas.onkeyup = function(e){
  keysDown[e.keyCode] = e.type == 'keydown';
  e.preventDefault();
  return false;
}
function isDown(key){
  return keysDown[key];
}
function resetMap(){
  keysDown = [];
  return false;
}

要检查按键是否按下,请在间隔循环或按键函数中使用isDown(keycode)
对于常规按键监听器:
canvas.onkeydown = canvas.onkeyup = function(e){
  // [...]
  if(isDown(17) && isDown(32)){ // Ctrl + Space
    alert('Ctrl and Space were pressed');
    resetMap();
  }
  e.preventDefault();
  return false;
}

为了实现类似于ActionScript 2.0的Key.isDown的快速按键监听器

function KeyLoop(){
  if(isDown(17) && isDown(32)){ // Ctrl + Space
    console.log('Lots of text');
    resetMap();
  }
  setTimeout(keyLoop,1000/24); // @ 24 fps
}
keyLoop();

我在这里放置了一个不同的操作,有两个原因:1)将alert()与重复间隔混合使用从来不是一个好主意,2)演示缺乏延迟,这使得它类似于AS2 Key.isDown()函数。要查看已记录的文本,请打开Firebug或常规JavaScript控制台。在Chrome中,按下CtrlShiftJ。在Firefox中,按下CtrlShiftK


通过在单击画布时聚焦于元素,这应该可以解决您的滚动问题。另一个好处是,由于您使用keysDown []作为原始事件的抽象,因此可以同时检查多个键,从而使制作8方向游戏变得容易。


经过进一步测试,我意识到它没有滚动到 span。实际上,它滚动到了 <input> 元素,这是我最初使用的元素。在 canvas.onclick 函数中,最好写入 document.body.scrollTop=canvas.offsetTop 以进行方向控制。虽然 canvas.focus() 可以自动定位到画布,但您会注意到它会在顶部或底部留下空间。 - Braden Best

0

你试过类似这样的吗?

<script type="text/javascript">
    canvas_active = false;
</script>

<canvas onfocus="javascript: canvas_active = true;" onblur="javascript: canvas_active = false;" />

然后在你当前的方法中检查canvas_active是否为true,如果是,则返回false,否则返回true。当然,这只有在用户在移动画布时一直将其聚焦时才会起作用。


这不是一个坏主意,尽管我更喜欢不使用内联JavaScript来分离关注点。 - Chris Sobolewski
1
一个画布元素是不可聚焦的。您可以使用 tabindex=0 使其可聚焦。 - pimvdb
不错,pimvdb。另外,Chris,你可以使用jQuery来绑定onfocus和onblur方法:$('#canvas_name').focus(function() { canvas_active = true; }); $('#canvas_name').blur(function() { canvas_active = false; }); - Furbeenator

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