Нажатие клавиши "Пробел" в игре сделает символьную охоту, нажимая клавишу "Пробел", когда поле подтверждения покажут, заставит это поле исчезнуть, и нажимающий клавишу "Пробел" в форме highscore добавит пространство в поле ввода. В этом примере существует несколько событий для того же ключа, но только один запущен за один раз.
Существует ли генерал (или специфичен для 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 */ };
Но это - очень запутывающий способ запрограммировать, так как определенные действия смешаны в функции-обработчике клавиши "Пробел", которая делает обслуживание трудно.
Что лучший способ состоит в том, чтобы обработать несколько событий для одного ключа, такого, что эти события только запущены при определенных обстоятельствах?
Функции - это первоклассные объекты в 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";
Все эти случаи будут обрабатываться одной функцией.Если вы хотите расширить с помощью другого случая, вы просто добавляете еще одну функцию к объекту действий. Обратите внимание, как все это заключено в один объект.
Есть несколько способов, обычно связанных с ветвлением кода для «специальной» модели событий 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;
}
вместо этого вы можете добавлять и удалять прослушиватель событий по мере необходимости.
предположим, что вы используете фреймворк 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 в интерфейсе и т. Д.
Прикрепите прослушиватели событий к отдельным элементам вместо всего документа.
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-библиотеку.