我有一个textarea,我想要从键盘或鼠标/编辑菜单捕获必要的事件。现在,当用户副本通过CTRL-V在textarea中粘贴文本时,将在 keydown 和粘贴上调用processUserInput两次,这是出于各种原因所不希望的。 / p> 我用这种方式“解决了”:
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 :(得分:4)
你正在做正确的方式。如果您更改keydown
的{{1}}会更好,但如果您愿意,可以让代码更时尚:
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;
}
来处理您的用户输入,这样您就无法冻结所有的UI线程,同时又不知道该过程。
会是这样的:
promisses
这是异步的示例,但您可以使用异步ajax或web-worker来处理事件,这样就不会冻结UI线程。
PS:超时不会阻止UI线程冻结,它只会将您的进程放在执行队列的末尾。
啊,另一个提示!
如果您正在处理textarea中的文本,那么最好使用$("#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);
}
而不是keypress
,因为如果您在keydown中获得textarea值,它将不会有更改,但是按键将获得你按下的键改变了值。
http://www.quirksmode.org/dom/events/keys.html
当然,如果您仍想使用keydown,可以使用我在示例中创建的keydown
推迟处理。