2010-06-29 80 views
10

按下游戲中的空格鍵將進行角色拍攝,當顯示確認框時按空格鍵將使該框消失,按高分表格中的空格鍵將在輸入框中添加空格。在這個例子中,同一個鍵有幾個事件,但是每次只有一個事件被觸發。在Javascript中處理多個關鍵事件的最佳方式是什麼?

是否有一個通用的(或特定的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

函數是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"; 

所有這些情況將由一個函數處理。如果您想要擴展另一個案例,您只需將其他功能添加到操作對象。注意整個事物是如何封裝到一個對象中的。

+0

我想這是最好的答案,謝謝!這個想法很好,我一定會使用它。我也會添加一個方法'addState(name,fn)',它使這個對象完成。感謝:] – Harmen 2010-06-29 20:30:58

+0

但仍然遠離處理這個問題的「最好的方式」。一個託管堆棧的處理程序更方便!由於這個問題很過時,如果有人有興趣,我可以開發。 – Pierre 2012-12-21 09:37:56

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庫來處理事件。

+1

這不是一個壞主意,但一般問題是,雖然'文檔'總是有焦點,'#遊戲'贏'除非你故意將焦點移動到其內部(如果用戶點擊並返回窗口,則可能會失去焦點)。 – bobince 2010-06-29 18:30:46

+0

嗯是的,我明白你在說什麼。 Web App的心態在這裏。這可能與植入拖拽元素或調整元素大小的功能類似,「mousemove」事件偵聽器必須附加到窗口或文檔上,否則一旦光標沒有在其位置更新之前懸停在該元素上方,事件就會停止觸發事件功能。好啊 – MooGoo 2010-06-29 18:47:13

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

除了當確認框沒有焦點時發生什麼(例如,未設置焦點,或者在用戶點擊遊戲區域時未重置焦點),在這種情況下確認框不再捕捉輸入 – 2010-06-29 18:31:52

+0

順便說一句,是否有任何理由不使用默認的運算符:'event = event || window.event'? – 2010-06-29 18:35:23

+0

這就是通常想要的;我不確定OP後的行爲。如果關鍵事件的來源不重要,並且只有時間有關係,那麼唯一的方法就是外部變量。 – bobince 2010-06-29 18:36:02

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按鈕觸發,等等......

相關問題