Обработка событий Javascript и управление потоком - PullRequest
5 голосов
/ 21 августа 2009

Я пытаюсь создать веб-страницу, которая загружается в зависимости от предоставленного ввода. У меня возникли проблемы с обработкой событий в JavaScript. Исходя из python, если бы я хотел дождаться определенного ввода с клавиатуры, прежде чем перейти к следующему отображаемому объекту, я бы создал цикл while и поместил бы слушатель ключа внутри него.

Python:

def getInput():
  while 1:
    for event in pygame.event.get(): #returns a list of events from the keyboard/mouse
      if event.type == KEYDOWN:
        if event.key == "enter": # for example
          do function()
          return
        elif event.key == "up":
          do function2()
          continue
        else: continue # for clarity

Пытаясь найти способ реализовать это в DOM / javascript, я, кажется, просто сбиваю страницу (полагаю, из-за цикла While), но я предполагаю, что это потому, что моя обработка событий плохо написана. Кроме того, регистрация обработчиков событий с помощью "element.onkeydown = function;" мне трудно обернуть голову, и setInterval (foo (), interval) не принес мне большого успеха.

По сути, я хочу, чтобы «слушающий» цикл выполнял определенное поведение для клавиши X, но прерывался при нажатии клавиши Y.

Ответы [ 7 ]

8 голосов
/ 21 августа 2009

В JavaScript вы отказываетесь от управления основным циклом. Браузер запускает основной цикл и перезванивает в ваш код, когда происходит событие или время ожидания / интервал. Вы должны обработать событие, а затем вернуться, чтобы браузер мог заниматься другими делами, запускать события и т. Д.

Таким образом, у вас не может быть цикла прослушивания. Браузер делает это за вас, давая вам событие и позволяя вам разобраться с ним, но как только вы закончите обрабатывать событие, вы должны вернуться. Вы не можете вернуться в другую петлю. Это означает, что вы не можете написать пошаговый процедурный код; если у вас есть состояние, которое сохраняется между вызовами событий, вы должны сохранить его, например. в переменной.

Этот подход не может работать:

<input type="text" readonly="readonly" value="" id="status" />

var s= document.getElementById('status');
s.value= 'Press A now';
while (true) {
    var e= eventLoop.nextKeyEvent(); // THERE IS NO SUCH THING AS THIS
    if (e.which=='a')
        break
}
s.value= 'Press Y or N';
while (true) {
    var e= eventLoop.nextKeyEvent();
    if (e.which=='y') ...

Пошаговый код необходимо вывернуть наизнанку, чтобы браузер вызывал вас, а не вы вызывали браузер:

var state= 0;
function keypressed(event) {
    var key= String.fromCharCode(event? event.which : window.event.keyCode); // IE compatibility
    switch (state) {
        case 0:
            if (key=='a') {
                s.value= 'Press Y or N';
                state++;
            }
            break;
        case 1:
            if (key=='y') ...
            break;
    }
}

s.value= 'Press A now';
document.onkeypress= keypressed;

Вы также можете сделать код более линейным и очистить некоторые элементы состояния с помощью вложенных анонимных функций:

s.value= 'Press A now';
document.onkeypress= function(event) {
    var key= String.fromCharCode(event? event.which : window.event.keyCode);
    if (key=='a') {
        s.value= 'Press Y or N';
        document.onkeypress= function(event) {
            var key= String.fromCharCode(event? event.which : window.event.keyCode);
            if (key=='y') ...
        };
    }
};
1 голос
/ 21 августа 2009

Для упрощения реализации обработки событий я рекомендую вам использовать библиотеку, такую ​​как Prototype или Jquery (Обратите внимание, что обе ссылки ведут к соответствующей документации по обработке событий.

Чтобы использовать их, нужно помнить 3 вещи:

  • Какой элемент DOM вы хотите наблюдать
  • Какое событие вы хотите захватить
  • Какое действие вызовет событие

Эти три пункта являются взаимоисключающими, и это означает, что вам нужно заботиться о трех при написании кода.

Итак, имея в виду, используя Prototype, вы можете сделать следующее:

Event.observe($('id_of_the_element_to_observe'), 'keypress', function(ev) {
  // the argument ev is the event object that has some useful information such
  // as which keycode was pressed.
  code_to_run;
});

Вот код более полезного примера, CharacterCounter (такой как найденный в Twitter, но, конечно, намного менее надежный;)):

var CharacterCounter = Class.create({

  initialize: function(input, counter, max_chars) {
    this.input = input;
    this.counter = counter;
    this.max_chars = max_chars;
    Event.observe(this.input, 'keypress', this.keyPressHandler.bind(this));
    Event.observe(this.input, 'keyup', this.keyUpHandler.bind(this));
  },

  keyUpHandler: function() {
    words_left = this.max_chars - $F(this.input).length;
    this.counter.innerHTML = words_left;
  },

  keyPressHandler: function(e) {
    words_left = this.max_chars - $F(this.input).length;
    if (words_left <= 0 && this.allowedChars(e.keyCode)) {
      e.stop();
    }
  },

  allowedChars: function(keycode) {
    // 8: backspace, 37-40: arrow keys, 46: delete
    allowed_keycodes = [ 8, 37, 38, 39, 40, 46 ];
    if (allowed_keycodes.include(keycode)) {
      return false;
    }
    return true
  }

});
1 голос
/ 21 августа 2009

вы не должны использовать такие циклы в javascript. в основном вы не хотите блокировать работу браузера. Таким образом вы работаете с событиями (onkeyup / down).

также вместо цикла вы должны использовать setTimeout, если хотите немного подождать и продолжить, если что-то произошло

Вы можете сделать что-то вроде этого:

<html>
<script>
var dataToLoad = new Array('data1', 'data2', 'data3' );
var pos = 0;
function continueData(ev) {
  // do whatever checks you need about key
  var ele = document.getElementById("mydata");
  if (pos < dataToLoad.length)
  {
     ele.appendChild(document.createTextNode(dataToLoad[pos]));
     pos++;
  }
}
</script>
<body onkeyup="continueData()"><div id="mydata"></div></body></html>

каждый раз при отпускании ключа добавляется следующее поле данных

0 голосов
/ 21 августа 2009

Проверьте слушатель ключа YUI

http://developer.yahoo.com/yui/docs/YAHOO.util.KeyListener.html

используя ключевой приемник, YUI позаботится о захвате любых событий. В javascript почти никогда не будет случая, когда вы должны ждать в цикле while, чтобы что-то произошло.

Если вам нужны примеры того, как работает обработка событий, посмотрите эти страницы.

http://developer.yahoo.com/yui/examples/event/eventsimple.html

0 голосов
/ 21 августа 2009

вы можете прикрепить прослушиватель событий к объекту окна следующим образом

window.captureEvents(Event.KEYPRESS);
window.onkeypress = output;
function output(event) {
  alert("you pressed" + event.which);
}
0 голосов
/ 21 августа 2009
document.onkeydown = function(e) {
  //do what you need to do
}

Это все, что нужно в javascript. Вам не нужно зацикливаться на ожидании события, когда бы оно ни происходило, эта функция будет вызываться, которая, в свою очередь, может вызывать другие функции и делать то, что нужно сделать. Думайте об этом как о том, что вместо того, чтобы ждать, пока произойдет то, что вы ищете, событие, которое вы ищете, сообщит вам, когда это произойдет.

0 голосов
/ 21 августа 2009

Любой хороший браузер зависнет, если встретится со слишком длинным скриптом. Это сделано для того, чтобы вредоносные веб-сайты не блокировали клиентское приложение.

Вы не можете иметь бесконечный цикл в JavaScript. Вместо этого присоедините прослушиватель событий к окну и укажите, что ваша обработка выполняется в обработчике (воспринимайте его как прерывания вместо опроса).

Пример:

function addEventSimple(obj,evt,fn) {
    if (obj.addEventListener)
        obj.addEventListener(evt,fn,false);
    else if (obj.attachEvent)
        obj.attachEvent('on'+evt,fn);
} // method pulled from quirksmode.org for cross-browser compatibility

addEventSimple(window, "keydown", function(e) {
    // check keys
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...