用户完成键入而不是按键时运行javascript函数?

Dav*_*hta 435 javascript keyboard jquery

我想在用户输入文本框时触发ajax请求.我不希望它在每次用户键入字母时都运行该函数,因为这会导致大量的ajax请求,但是我不希望它们也必须按下回车按钮.

有没有办法可以检测用户何时完成输入然后执行ajax请求?

在这里使用jQuery!戴夫

Sur*_*ams 632

所以,我猜猜完成打字就意味着你停了一会儿,说5秒钟.因此,考虑到这一点,让我们在用户释放密钥时启动计时器,并在按下密钥时清除它.我决定有问题的输入是#myInput.

做一些假设......

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 5000;  //time in ms, 5 second for example
var $input = $('#myInput');

//on keyup, start the countdown
$input.on('keyup', function () {
  clearTimeout(typingTimer);
  typingTimer = setTimeout(doneTyping, doneTypingInterval);
});

//on keydown, clear the countdown 
$input.on('keydown', function () {
  clearTimeout(typingTimer);
});

//user is "finished typing," do something
function doneTyping () {
  //do something
}
Run Code Online (Sandbox Code Playgroud)

  • 此答案无法正常工作,除非用户输入速度非常慢,否则它将始终在5秒后触发.见下面的工作方案. (21认同)
  • 谢谢:)我开始在问题上输入我的评论,并意识到我有一个不错的主意. (4认同)
  • 如果你在这里遇到麻烦,因为计时器立即触发,试着在函数调用周围添加引号:setTimeout('functionToBeCalled',doneTypingInterval); (3认同)
  • 我看到一些注释,其中示例中的回调函数`doneTyping`立即运行.这通常是在函数名后意外包含`()`的结果.注意它应该是`setTimeout(doneTyping,`not`setTimeout(doneTyping(),` (3认同)
  • 当您将数据复制/粘贴到字段中时不起作用。 (2认同)
  • @Jessica要使用粘贴,您必须添加“ paste”事件,如下所示:on('keyup paste', (2认同)
  • 我废弃了单独的`keydown`函数,只是将它添加到第一个函数中.我还在那里添加了变化.所以它看起来像这个`twitterUsernameField.on('keyup keydown change',function(){`它似乎工作得很好...... (2认同)

goi*_*ing 369

上面选择的答案不起作用.

因为打字定时器被多次设置(在快速打字机等触发keydown之前按两次键盘)然后它没有正确清除.

下面的解决方案解决了这个问题,并在OP请求完成后调用X秒.它也不再需要冗余的keydown功能.我还添加了一个检查,以便在输入为空时不会发生函数调用.

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 5000;  //time in ms (5 seconds)

//on keyup, start the countdown
$('#myInput').keyup(function(){
    clearTimeout(typingTimer);
    if ($('#myInput').val()) {
        typingTimer = setTimeout(doneTyping, doneTypingInterval);
    }
});

//user is "finished typing," do something
function doneTyping () {
    //do something
}
Run Code Online (Sandbox Code Playgroud)

和vanilla JavaScript解决方案中的相同代码:

//setup before functions
let typingTimer;                //timer identifier
let doneTypingInterval = 5000;  //time in ms (5 seconds)
let myInput = document.getElementById('myInput');

//on keyup, start the countdown
myInput.addEventListener('keyup', () => {
    clearTimeout(typingTimer);
    if (myInput.value) {
        typingTimer = setTimeout(doneTyping, doneTypingInterval);
    }
});

//user is "finished typing," do something
function doneTyping () {
    //do something
}
Run Code Online (Sandbox Code Playgroud)

这个解决方案确实使用ES6,但这里没有必要.只需更换letvar并用常规的功能箭头功能.

  • 使用`$('#myInput').on('input',function(){`如果你想让它与拷贝和粘贴一起工作.我没有看到检查点输入是否为空.假设他想要擦除他输入的内容将无法进行ajax调用. (9认同)
  • 我认为我们还应该考虑用户只是在字段内粘贴字符串的情况. (7认同)
  • 好吧,即使输入为空,仍然可以调用该函数.如果要在输入再次为空时清除某些搜索结果(例如),该怎么办? (5认同)
  • 为什么不使用$(this).val()? (4认同)
  • 为什么它是`if($('#myInput').val)`而不是`if($('#myInput').val())`?`.val`应该是一个函数吗? (3认同)
  • 对我来说,它立即调用该函数:/不是在5秒之后,我尝试增加时间,但同样的事情发生了 (3认同)

bit*_*xel 72

它只有一行 with underscore.js去抖功能:

$('#my-input-box').keyup(_.debounce(doSomething , 500));
Run Code Online (Sandbox Code Playgroud)

这基本上是在我停止打字后500毫秒的doSomething.

欲了解更多信息:http://underscorejs.org/#debounce

  • 令人惊讶的是,人们如何吹捧"一行代码"至关重要.大.一行代码,需要加载1.1k JS文件.我不是在贬低这个因为是一个解决方案.但是一行大胆的东西让我感到烦恼,并导致膨胀代码. (53认同)
  • @Wolfie,我同意你关于代码膨胀的看法,但 Underscore 和 Lodash 是 [NPM](https://www.npmjs.com/) 上两个最依赖的实用程序,所以这对很多人来说可能是一个单行解决方案. (6认同)
  • 似乎也可用于jQuery:http://code.google.com/p/jquery-debounce/和https://github.com/diaspora/jquery-debounce (5认同)
  • @Paul我同意,如果您出于其他目的加载库,则使用通用代码很好而且实际上是有益的。但是,为了一行代码的目的而加载K的代码效率不高。尤其是随着移动平台变得越来越少的无限数据。而且许多欧元区也通过数据为互联网付费。因此,在合理的时候注意good肿是一件好事。 (2认同)
  • 如果这就是你所需要的,你可以得到 debouce() 函数,https://www.npmjs.com/package/debounce。工作得很好。 (2认同)

Mar*_*rko 43

是的,您可以在每个启动事件上设置2秒的超时,这将触发ajax请求.您还可以存储XHR方法并在随后的按键事件中将其中止,以便您节省带宽甚至更多.这是我为自己的自动完成脚本编写的内容.

var timer;
var x;

$(".some-input").keyup(function () {
    if (x) { x.abort() } // If there is an existing XHR, abort it.
    clearTimeout(timer); // Clear the timer so we don't end up with dupes.
    timer = setTimeout(function() { // assign timer a new timeout 
        x = $.getJSON(...); // run ajax request and store in x variable (so we can cancel)
    }, 2000); // 2000ms delay, tweak for faster/slower
});
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助,

马尔科


Gra*_*Fox 39

迟到的答案,但我添加它是因为它是 2019 年,这完全可以使用漂亮的 ES6 实现,没有第三方库,而且我发现大多数评价很高的答案都很笨重,而且变量太多。

来自这篇优秀博客文章的优雅解决方案

function debounce(callback, wait) {
  let timeout;
  return (...args) => {
      clearTimeout(timeout);
      timeout = setTimeout(function () { callback.apply(this, args); }, wait);
  };
}

window.addEventListener('keyup', debounce( () => {
    // code you would like to run 1000ms after the keyup event has stopped firing
    // further keyup events reset the timer, as expected
}, 1000))
Run Code Online (Sandbox Code Playgroud)

  • 这确实应该是今年的最佳答案 (3认同)
  • @Akhila,如果您对问题的描述是“它不起作用”,我无法帮助您。考虑打开您自己的问题并链接回此线程。和平。 (3认同)

azz*_*y81 17

var timer;
var timeout = 1000;

$('#in').keyup(function(){
    clearTimeout(timer);
    if ($('#in').val) {
        timer = setTimeout(function(){
            //do stuff here e.g ajax call etc....
             var v = $("#in").val();
             $("#out").html(v);
        }, timeout);
    }
});
Run Code Online (Sandbox Code Playgroud)

这里有完整的例子:http://jsfiddle.net/ZYXp4/8/


Lia*_*gan 10

我喜欢Surreal Dream的答案,但我发现我的"doneTyping"功能会触发每个按键,即如果你真的很快输入"Hello"; 当你停止输入时,该功能只会发射一次,而不是只发射一次.

问题是javascript setTimeout函数似乎没有覆盖或杀死已设置的任何旧超时,但如果你自己这样做它就可以了!所以我只是在setTimeout之前添加了一个clearTimeout调用,如果设置了typingTimer.见下文:

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 5000;  //time in ms, 5 second for example

//on keyup, start the countdown
$('#myInput').on("keyup", function(){
    if (typingTimer) clearTimeout(typingTimer);                 // Clear if already set     
    typingTimer = setTimeout(doneTyping, doneTypingInterval);
});

//on keydown, clear the countdown 
$('#myInput').on("keydown", function(){
    clearTimeout(typingTimer);
});

//user is "finished typing," do something
function doneTyping () {
    //do something
}
Run Code Online (Sandbox Code Playgroud)

NB我本来希望将此作为对Surreal Dream答案的评论添加,但我是新用户并且没有足够的声誉.抱歉!


Fab*_*ler 10

声明以下delay函数:

var delay = (function () {
    var timer = 0;
    return function (callback, ms) {
        clearTimeout(timer);
        timer = setTimeout(callback, ms);
    };
})()
Run Code Online (Sandbox Code Playgroud)

然后使用它:

let $filter = $('#item-filter');
$filter.on('keydown', function () {
    delay(function () {            
        console.log('this will hit, once user has not typed for 1 second');            
    }, 1000);
});    
Run Code Online (Sandbox Code Playgroud)


Jec*_*oms 9

修改已接受的答案以处理其他案例,例如粘贴:

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 2000;  //time in ms, 2 second for example
var $input = $('#myInput');

// updated events 
$input.on('input propertychange paste', function () {
    clearTimeout(typingTimer);
    typingTimer = setTimeout(doneTyping, doneTypingInterval);      
});

//user is "finished typing," do something
function doneTyping () {
  //do something
}
Run Code Online (Sandbox Code Playgroud)


YSF*_*BDY 9

前两个答案都不适合我.所以,这是我的解决方案:

var timeout = null;

$('#myInput').keyup(function() {
    clearTimeout(timeout);

    timeout = setTimeout(function() {
        //do stuff here
    }, 500);
});
Run Code Online (Sandbox Code Playgroud)


小智 8

const inText = document.getElementById('inText')
const outText = document.getElementById('outText')
const delay = 1000

let timer
inText.addEventListener('input', code => {
  clearTimeout(timer);
  timer = setTimeout(x => {
    outText.innerHTML = inText.value
  }, delay, code)
})
Run Code Online (Sandbox Code Playgroud)
<textarea id='inText'>edit this and...</textarea>
<pre id='outText'>see the results after you stop typing for one second</pre>
Run Code Online (Sandbox Code Playgroud)


Raf*_*zak 5

我认为在这种情况下,keyDown事件不是必需的(请告诉我为什么我错了)。在我的(非jquery)脚本中,类似的解决方案如下所示:

var _timer, _timeOut = 2000; 



function _onKeyUp(e) {
    clearTimeout(_timer);
    if (e.keyCode == 13) {      // close on ENTER key
        _onCloseClick();
    } else {                    // send xhr requests
        _timer = window.setTimeout(function() {
            _onInputChange();
        }, _timeOut)
    }

}
Run Code Online (Sandbox Code Playgroud)

这是我对Stack Overflow的第一个答复,所以我希望有一天能对某人有所帮助:)