【问题标题】:Disable arrow keys from scrolling only when user is interacting with <canvas>仅当用户与 <canvas> 交互时禁用箭头键滚动
【发布时间】:2011-11-28 00:33:47
【问题描述】:

我在 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;
})

编辑:

下面的答案很好地说明了如何确保画布被聚焦,但我仍然很困惑为什么在返回 false 的 EventListener 函数中返回 false 不会禁用滚动。

【问题讨论】:

    标签: javascript scroll addeventlistener html5-canvas event-listener


    【解决方案1】:

    只要您以某种方式赋予画布焦点(即 canvas.tabIndex = 1;),那么您只需在 return false 之前添加 e.preventDefault() 即可。

    例子:

    http://jsfiddle.net/faAkN/

    【讨论】:

    • 谢谢。为我工作!
    【解决方案2】:

    我遇到了类似的问题,并想出了一个解决办法。

    这是我想出的:

    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;
    }
    

    要检查某个键是否按下,请在间隔循环或 keydown 函数中使用 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 @987654327 相似@ 功能。要查看记录的文本,请调出 firebug 或常规 JavaScript 控制台。在 Chrome 中,即 CtrlShiftJ。在 Firefox 中,CtrlShiftK.


    当您单击画布时,这应该可以通过关注元素来解决您的滚动问题。另一个好处是您可以一次检查多个键,因为您使用 keysDown[] 作为原始事件的抽象,从而轻松制作 8 向游戏。

    【讨论】:

    • 进一步测试后,我意识到它没有滚动到跨度。它实际上滚动到 &lt;input&gt; 元素,这是我最初使用的。为方向写的最好的东西是canvas.onclick 函数中的document.body.scrollTop=canvas.offsetTop。虽然canvas.focus() 会自动定位到画布,但您会注意到它在顶部或底部留下空间。
    【解决方案3】:

    你尝试过这样的事情吗?

    <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 来分离关注点。
    • 画布元素不可聚焦。您可以使用tabindex=0 使其具有焦点。
    • 不错,pimvdb。另外,Chris,您可以使用 jQuery 来绑定 onfocus 和 onblur 方法:$('#canvas_name').focus(function() { canvas_active = true; });$('#canvas_name').blur(function() { canvas_active = false; });
    猜你喜欢
    • 1970-01-01
    • 2018-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多