2009-08-21 17 views
5

Estoy intentando crear una página web que se carga dependiendo de la entrada proporcionada. Tengo problemas para manejar el manejo de eventos en javascript, básicamente. Viniendo de Python, si quería esperar una entrada de teclado específica antes de pasar al siguiente objeto para mostrar, crearía un mientras que el loop y pondría un oyente clave dentro de él.Gestión de eventos de Javascript y control de flujo

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 

Al tratar de encontrar una manera de implementar esto en DOM/JavaScript, parece que acaba de chocar la página (supongo que debido a la estructura While), pero Supongo que esto se debe a mi manejo de eventos está mal escrito. Además, registrar los controladores de eventos con "element.onkeydown = function;" me resulta difícil envolver mi cabeza, y setInterval (foo(), interval] no me ha traído mucho éxito.

Básicamente, quiero que un bucle de "escucha" haga cierto comportamiento para la tecla X, pero romperse cuando es golpeado tecla Y.

Respuesta

8

En JavaScript, ceder el control del bucle principal. El navegador ejecuta el ciclo principal y devuelve la llamada al código cuando ocurre un evento o tiempo/intervalo. Tienes que manejar el evento y luego regresar para que el navegador pueda continuar haciendo otras cosas, disparando eventos, y así sucesivamente.

De modo que no puede tener un bucle de "escucha". El navegador hace eso por ti, dándote el evento y permitiéndote lidiar con él, pero una vez que hayas terminado de manejar el evento, debes regresar. No puedes volver a caer en un ciclo diferente. Esto significa que no puede escribir código de procedimiento paso a paso; si tiene un estado que persiste entre llamadas a eventos, debe almacenarlo, p. ej. en una variable.

Este enfoque no puede funcionar:

<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') ... 

Paso a paso código tiene que ser vuelto del revés para que el navegador llama a que, en vez de llamar al navegador:

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; 

también puede hacer que el código se ven un poco más lineal y limpiar algo de la materia estado utilizando anidados funciones anónimas:

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

Gracias Bobince. Su comentario sobre qué código de procedimiento paso a paso solucionó mi problema muy bien. Desearía tener suficientes representantes para votarte. – intelligencer

1

no debe utilizar este tipo de bucles en javascript. básicamente usted no desea bloquear el navegador haga su trabajo. de esta manera se trabaja con eventos (onkeyup/abajo).

también en lugar de un bucle, debe usar setTimeout si desea esperar un poco y continuar si sucedió algo

puede hacer algo así:

<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> 

cada vez que una tecla se libera el campo de datos siguiente se añade

+0

Si necesita usar el objeto de evento en un controlador, ese 'ev' realmente debería ser un' evento', ya que ese es el nombre con el que se pasa a una función. IE, por supuesto, está siendo "especial" y asigna un objeto de evento a un 'window.event' global en lugar de pasarlo a la función del controlador de eventos bajo' event'. – kangax

+0

cierto - obviamente necesita ajustar el código para actuar en diferentes pulsaciones de teclas/lanzamientos. Estaba intentando demostrar cómo solfear el problema while-loop – Niko

0

Cualquier buen navegador se colgará cuando encuentra un script que se ejecuta demasiado tiempo. Esto es para evitar que sitios web maliciosos bloqueen la aplicación cliente.

No puede tener un bucle infinito en javascript. En su lugar, adjunte un detector de eventos a la ventana y apunte a su procesamiento en el controlador (piénselo como interrupciones en lugar de sondeo).

Ejemplo:

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 
}); 
0
document.onkeydown = function(e) { 
    //do what you need to do 
} 

Eso es todo lo que se necesita en javascript. No necesita hacer un bucle para esperar a que ocurra el evento, cada vez que ocurra el evento se llamará a esa función, que a su vez puede llamar a otras funciones, haga lo que sea necesario hacer. Piense en ello como que en lugar de tener que esperar que ocurra el evento que busca, el evento que busca le avisará cuando ocurra.

0

podría adjuntar un detector de eventos al objeto ventana como esta

window.captureEvents(Event.KEYPRESS); 
window.onkeypress = output; 
function output(event) { 
    alert("you pressed" + event.which); 
} 
1

Para una implementación más sencilla del manejo de eventos, le recomiendo usar una biblioteca como Prototype o Jquery (Tenga en cuenta que ambos enlaces lo llevan a su respectiva documentación de manejo de eventos.

Con el fin de utilizarlos hay que tener en cuenta 3 cosas:

  • ¿Qué elemento DOM que desea observar
  • qué evento que desea capturar
  • Qué acción será la activación de un evento

Estos tres puntos son mutuamente inclusivos, lo que significa que debe ocuparse de los 3 al escribir el código.

Así que tener esto en mente, usando Prototype, usted puede hacer esto:

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; 
}); 

Aquí está el código de un ejemplo más útil, un CharacterCounter (como la encontrada en Twitter, pero seguramente mucho menos fiable;)):

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 
    } 

}); 
Cuestiones relacionadas