禁用用户浏览器中的箭头键滚动

114

我正在使用canvas和javascript制作游戏。

当页面比屏幕更长(包括评论等)时,按下箭头会使页面向下滚动,这将导致游戏无法进行。

有什么方法可以防止玩家在想向下移动时窗口自动滚动?

我猜对于Java游戏等,只要用户点击了游戏就没有这个问题。

我尝试了如何禁用Firefox中的箭头键页面滚动中的解决方案,但是我无法使其工作。

4个回答

204

概述

简单地 阻止默认的 浏览器行为:

window.addEventListener("keydown", function(e) {
    if(["Space","ArrowUp","ArrowDown","ArrowLeft","ArrowRight"].indexOf(e.code) > -1) {
        e.preventDefault();
    }
}, false);

如果您需要支持Internet Explorer或其他旧浏览器,请使用e.keyCode而不是e.code,但请注意keyCode 已被弃用,您需要使用实际的代码而不是字符串:

// Deprecated code!
window.addEventListener("keydown", function(e) {
    // space and arrow keys
    if([32, 37, 38, 39, 40].indexOf(e.keyCode) > -1) {
        e.preventDefault();
    }
}, false);

原始回答

我在自己的游戏中使用了以下函数:

var keys = {};
window.addEventListener("keydown",
    function(e){
        keys[e.code] = true;
        switch(e.code){
            case "ArrowUp": case "ArrowDown": case "ArrowLeft": case "ArrowRight":
            case "Space": e.preventDefault(); break;
            default: break; // do not block other keys
        }
    },
false);
window.addEventListener('keyup',
    function(e){
        keys[e.code] = false;
    },
false);

魔法发生在 e.preventDefault(); 中。 这将阻止事件的默认操作,本例中是浏览器移动视角。
如果您不需要当前按钮状态,只需删除 keys,并在箭头键上放弃默认操作即可。
var arrow_keys_handler = function(e) {
    switch(e.code){
        case "ArrowUp": case "ArrowDown": case "ArrowLeft": case "ArrowRight": 
            case "Space": e.preventDefault(); break;
        default: break; // do not block other keys
    }
};
window.addEventListener("keydown", arrow_keys_handler, false);

请注意,这种方法还可以使您稍后删除事件处理程序,以便在需要重新启用箭头键滚动时使用:
window.removeEventListener("keydown", arrow_keys_handler, false);

参考资料


10
我非常喜欢这个解决方案,但似乎在Chrome中无法工作 =/ - Kaninepete
1
如果您这样做,并且您的网页上有任何字段输入,那么您将无法使用空格键或箭头键来导航文本。我发现这是一个很大的缺点。 - Single Entity
14
请注意,您确实需要使用keydown而不是keyup - Ludder
1
这在Chrome中仍然不起作用 :( 我的贪吃蛇游戏挂了 - Mister SirCode
1
对于任何试图使用keyCode的人,请注意https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode已被弃用。请改用code https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code - A.D
显示剩余6条评论

7
为了易于维护,我会将“阻止”处理程序附加到元素本身上(在您的情况下,是canvas)。

theCanvas.onkeydown = function (e) {
    if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
        e.view.event.preventDefault();
    }
}

为什么不直接使用window.event.preventDefault()MDN中指出:

window.event是Microsoft Internet Explorer的专有属性,只能在调用DOM事件处理程序时使用。其值是当前正在处理的事件对象。

进一步阅读:


我已经为此奋斗了几个小时,而你解决了它。谢谢你! - Dan Barron

2

我尝试了多种方法来阻止箭头键滚动,包括jQuery和本地JavaScript - 它们在Firefox中都很好用,但在最近的Chrome版本中不起作用。
即使是{passive: false}属性也无法解决此问题,这被推荐为唯一有效的解决方案,例如这里

最终,在尝试了许多次之后,我找到了一种在Firefox和Chrome中都适用的方法:

window.addEventListener('keydown', (e) => {
    if (e.target.localName != 'input') {   // if you need to filter <input> elements
        switch (e.keyCode) {
            case 37: // left
            case 39: // right
                e.preventDefault();
                break;
            case 38: // up
            case 40: // down
                e.preventDefault();
                break;
            default:
                break;
        }
    }
}, {
    capture: true,   // this disables arrow key scrolling in modern Chrome
    passive: false   // this is optional, my code works without it
});

EventTarget.addEventListener()的报价来自MDN

options 可选
   一个选项对象指定有关事件监听器的特性。可用选项如下:

capture
   一个布尔值,指示此类型的事件将在分派到 DOM 树中它下面的任何 EventTarget 之前分派到已注册的 listener
once
   ...
passive
   一个布尔值,如果为 true,则表示由 listener 指定的函数永远不会调用 preventDefault()。如果被动侦听器确实调用了 preventDefault(),则用户代理除生成控制台警告外将什么也不做。...


0

这是针对 React 重写的已接受答案。

import { useEffect } from "react";

const usePreventKeyboardScrolling = () => {
  const onKeyDown = (e) => {
    if (
      ["Space", "ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].indexOf(
        e.code
      ) > -1
    ) {
      e.preventDefault();
    }
  };

  useEffect(() => {
    window.addEventListener("keydown", onKeyDown, false);
    return () => window.removeEventListener("keydown", onKeyDown);
  });
};

export { usePreventKeyboardScrolling };

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