在Javascript中处理多个关键事件的最佳方法是什么?

时间:2010-06-29 18:12:00

标签: javascript events event-handling

在游戏中按空格键会进行角色拍摄,当显示确认框时按空格键会使此框消失,按高分形式按空格键将在输入框中添加空格。在此示例中,同一个键有几个事件,但一次只触发一个。

是否有一般(或特定于Javascript)方法或编程方式将事件添加到某个键,因此它们只在某些情况下执行?

当然可以这样做:

var inGame = true|false;
var inConfirmationBox = true|false;

function spaceBarHandler(){
    if(inGame){ /*shoot*/}
    else if(inConfirmationBox){ /*remove box*/}
}

document.onkeydown = function(){ /* call space bar handler if space bar was pressed */ };

但这是一种非常令人困惑的编程方式,因为特定的动作在空格键处理函数中混合在一起,这使维护变得困难。

处理一个键的多个事件的最佳方法是什么,这样只会在某些情况下触发这些事件?

4 个答案:

答案 0 :(得分:4)

函数是javascript中的第一类对象,这使它们非常强大。因此,您的问题可以非常优雅地解决。

// the whole thing can be encapsulated 
// into an object actually

function spaceBarHandler() {
  var state = spaceBarHandler.state;
  var actions = spaceBarHandler.actions;

    // execute function if exists
    if (actions[state]) {
      actions[state]();
    }
}

// spaceBar actions
spaceBarHandler.actions = {
  shoot: function() {
    // bang bang
  },
  removeBox: function() {
    // do it...
  }
};

// change current state from outside
// we are in the game
spaceBarHandler.state = "shoot";

// change current state from outside
// confirmation box is shown 
spaceBarHandler.state = "removeBox";

所有这些案例都将由一个函数处理。如果要扩展另一个案例,只需向actions对象添加另一个函数即可。注意如何将整个事物封装到一个对象中。

答案 1 :(得分:0)

将事件监听器附加到单个元素而不是整个文档。

document.getElementById('highscore').onkeypress = function(keyEvent) {
      if (is_spacebar(keyEvent)) //Do something...
};

document.getElementById('game').onkeypress = function(keyEvent) {
      if (is_spacebar(keyEvent)) //Do something else...
};

这是一个简单的例子。您可能必须处理事件冒泡,当使用addEventListener()将函数附加到事件时,可以控制事件冒泡。鉴于涉及此问题的浏览器(IE)兼容性问题,应该使用一些JS库来处理事件。

答案 2 :(得分:0)

有几种方法,通常涉及IE的“特殊”事件模型的代码分支。

一种方法是停止从按钮冒泡到文档密钥处理程序进一步处理的按键:

confirmationbox.onkeydown = function(event) {
    if (event === undefined) event = window.event;

    // do something with event.keyCode

    if ('stopPropagation' in event) // standards browsers
        event.stopPropagation();
    else if ('cancelBubble' in event) // IE before version 9
        event.cancelBubble = true;
};

document.onkeydown = ... // will not be called for keydowns inside confirmationbox

另一种方法是检查事件目标元素以查看它是否在框中:

document.onkeydown = function(event) {
    if (event === undefined) event = window.event;
    var target = 'target' in event ? event.target : event.srcElement; // srcElement is for IE<9

    if (target === containerbox || isDescendantOf(target, containerbox) {
        // do containerbox stuff
    } else {
        // do other stuff
    }
};

function isDescendantOf(element, ancestor) {
    while (element = element.parentNode)
        if (element === ancestor)
            return true;
    return false;
}

答案 3 :(得分:0)

您可以根据需要添加和删除事件侦听器。

让我们假设你正在使用一个javascript框架(如果你不是,那么你可能应该考虑像这样的游戏中涉及的JS代码量)。

使用PrototypeJS:

比赛开始时,

document.observe("keydown",shootHandler());

创建消息框时

function createBox(text) {
    ...snip

    document.observe("keydown",closeBox());
    document.fire("game:pause");
}

,例如

var paused = false;

function shoothandler() {
   if (!paused) {
       alert("pew! pew!");
   }
}

function closeBox() {
    $('messagebox').remove();
    document.fire("game:unpaused");
    document.stopObserving("keydown",closeBox());
}

document.observe("game:paused", function() { paused = true;});
document.observe("game:unpaused", function() { paused = false;});
document.observe("game:over", function() { document.stopObserving("keydown",shootHandler());});

我没有包括高分屏幕,但理论是一样的。

如您所见,我还使用自定义事件来通知暂停状态。同样的事件也可以通过界面中的puase按钮等来触发......