2009-08-21 66 views
5

我試圖構建一個網頁,根據提供的輸入加載。基本上,我在javascript事件處理方面遇到了一些麻煩。來自python,如果我想等待一個特定的鍵盤輸入,然後移動到下一個要顯示的對象,我會創建一個,而循環並在其中放置一個關鍵偵聽器。Javascript事件處理和流量控制

的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被打破裂。

回答

8

在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

感謝bobince。您對有關逐步程序代碼的評論很好地解決了我的問題。希望我有足夠的代表讓你高興。 – intelligencer 2009-08-21 16:03:13

1

在JavaScript中你不應該用這樣的循環。基本上你不想從做它的工作阻止瀏覽器。因此,你使用這些事件(的onkeyup /下)。

也而不是一個循環,你應該使用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

如果你需要在一個處理程序中使用事件對象,那麼'ev'應該是一個'event',因爲這是它傳遞給函數的名字。 IE當然是「特殊的」,並將事件對象分配給全局的「window.event」,而不是將它傳遞給'event'下的事件處理函數。 – kangax 2009-08-21 15:20:05

+0

是真的 - 你顯然需要調整代碼來處理不同的按鍵/釋放。我試圖演示如何解決while-loop問題 – Niko 2009-08-21 15:22:43

0

任何一個優秀的瀏覽器在遇到運行時間過長的腳本會崩潰。這是爲了防止惡意網站鎖定客戶端應用程序。

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

這一切都需要在JavaScript。您不需要循環等待事件發生,只要發生該事件,該函數將被調用,進而可以調用其他函數,執行任何需要完成的操作。把它想象成是你不必等待事件的發生,你所尋找的事件會在事件發生時讓你知道。

0

你可以附加一個事件監聽器窗口對象這樣

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

爲了更容易實現事件處理,我建議您使用一個庫,例如PrototypeJquery(請注意,這兩個鏈接會將您帶到各自的事件處理文檔。

爲了使用它們,你必須記住三兩件事:

  • 要觀察
  • 你想捕捉
  • 什麼動作什麼事件有什麼DOM元素將事件觸發

這三點是相互包容的,這意味着您在編寫代碼時需要注意3點。

所以銘記這一點,使用原型,你可以這樣做:

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 
    } 

});