4

我有一个文本区域,我想从键盘或鼠标/编辑菜单中捕获必要的事件。现在,当用户通过 CTRL-V 在文本区域中复制粘贴文本时,processUserInput 会被调用两次,无论是在keydown还是在粘贴时,由于各种原因,这是不可取的。

我以这种方式“解决”了它:

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

我想知道这个问题是否有更优雅的解决方案。

ps 需要 onpaste 事件,因为用户可以通过鼠标右键单击或通过浏览器编辑菜单复制粘贴文本。

提前致谢!

4

1 回答 1

5

你做对了伙计。如果你改变keydownfor会更好keypress,但如果你愿意,你可以让你的代码变得时尚:

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

但是,如果我愿意,我将使用 apromisses来处理您的用户输入处理,这样您就不能在等待进程时冻结所有 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-worker 来处理您的事件,这样您就不会冻结 UI 线程。

PS.:超时不会阻止 UI 线程冻结,它只会将您的进程置于执行队列的末尾。

啊,另一个提示!

如果您正在处理 textarea 中的文本,那么您最好使用它keypresskeydown因为如果您在 keydown 中获取 textarea 值,它将不会有任何更改,但是按键将通过您按下的键来更改值。

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

当然,如果您仍想使用 keydown,您可以使用setTimeout我在示例中所做的延迟处理。

于 2013-01-06T20:19:26.277 回答