2013-01-06 61 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正如我在开始时所说的,你正处于正确的道路上,我的朋友。我不知道你的流程有多沉重,但请记住,如果流量很大,如果你在网络工作者或任何其他非阻塞解决方案中使用,你的用户会感谢你。 :) –