2013-01-06 82 views
3

我有一個textarea,我想要從鍵盤或鼠標/編輯菜單捕獲必要的事件。現在,當用戶複製通過CTRL-V在textarea中粘貼文本時,processUserInput被調用兩次,分別在keydown粘貼上,這是由於各種原因而不希望的。關於輸入問題的textarea

我已經「解決」這樣說:

var IsProcessingEvent = false; 

$("#textarea").on('click keydown cut paste', processUserInput); 

function processUserInput(e) { 
    if(!IsProcessingEvent) { 
     IsProcessingEvent = true; 
     // do the actual processing of user input 
     IsProcessingEvent = false; 
    } 
} 

我不知道是否有一個更優雅的解決這個問題。

p.s onpaste事件是需要的,因爲用戶可以通過鼠標右鍵點擊或通過瀏覽器編輯菜單複製粘貼文本。

在此先感謝!

+0

不確定,但嘗試使用event.stopPropagation() – sdespont

+0

@sdespont將無法正常工作,因爲它們是不同的事件。它會停止keydown傳播,然後執行過去並停止傳播。 –

回答

4

你正在做正確的方式傢伙。

var isProcessingEvent = false; 

$("#textarea").on('click keypress cut paste', processUserInput); 

function processUserInput(e) { 
    // Is processing event, so stop here. 
    if(isProcessingEvent) { 
     return; 
    } 
    isProcessingEvent = true; 

    // do the actual processing of user input 

    isProcessingEvent = false; 
} 

但是,如果我想你,我會用一個promisses與用戶輸入的處理工作,這樣你:只要你改變​​爲keypress,但你可以得到你的代碼的時尚,如果你想更好的無法在處理過程中凍結所有UI線程。

會是這樣的:

$("#textarea").on('click keypress cut paste', processUserInput); 

function processUserInput(e) { 
    // Is processing event, so stop here. 
    if(processUserInput.working) { 
     // The user trigger the event while it was processing 
     processUserInput.doAgain = { 
      // save context 
      ctx: this, 
      // save event 
      e: e 
     }; 
     return; 
    } 
    processUserInput.working = true; 

    function finished() { 
     processUserInput.working = false; 

     // The process finished but has new changes in the textfield so... 
     var lastEvent = processUserInput.doAgain; 
     if (lastEvent) { 
      processUserInput.doAgain = null; 

      // Process this guy again 
      setTimeout(processUserInput.bind(lastEvent.ctx), 0, lastEvent.e); 
     } 
    } 

    function theProcess(e, cb) { 

     // do my async stuff here 

     // Unfreeze the click/keydown/cut/past events in the textarea 
     if (typeof cb === 'function') { 
      cb(); 
     } 
    } 

    setTimeout(theProcess.bind(this), 0, e, finished); 
} 

這是異步一個例子,但你可以使用一個異步Ajax或web的工人來處理您的活動,這樣你就不會凍結UI線程。

PS .:超時不會阻止UI線程凍結,它只會將您的進程放到執行隊列的末尾。

Ahh另一個提示!

如果您正在處理textarea中的文本,那麼最好使用keypress而不是​​,因爲如果您在keydown中獲得textarea值,它將不會有更改,但按鍵會獲得由您更改的值正在緊迫。

http://www.quirksmode.org/dom/events/keys.html

當然,如果你仍然想使用的keydown,你可以使用我的例子進行了setTimeout推遲處理。

+1

感謝您的提示。我使用的是keydown,因爲我需要在textarea更改之前獲取數據,所以所有這些事件都會在更改textarea數據之前觸發。然後在1ms的超時時間之後,我在數據更改之後在textarea中進行了更多處理。 – MIrrorMirror

+0

@MIrrorMirror正如我在開始時所說的,你正處於正確的道路上,我的朋友。我不知道你的流程有多沉重,但請記住,如果流量很大,如果你在網絡工作者或任何其他非阻塞解決方案中使用,你的用戶會感謝你。 :) –