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

IT技术 javascript jquery keyboard
2021-02-01 18:06:58

当用户在文本框中输入完成时,我想触发一个 ajax 请求。我不希望它在每次用户键入字母时都运行该函数,因为这会导致很多 ajax 请求,但是我也不希望他们必须点击输入按钮。

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

在这里使用jQuery!戴夫

6个回答

所以,我猜想完成打字意味着你只是停下来一段时间,比如 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
}
如果您在这里遇到麻烦,因为计时器会立即触发,请尝试在函数调用周围添加引号: setTimeout('functionToBeCalled', doneTypingInterval);
2021-03-25 18:06:58
此答案无法正常工作,除非用户键入非常慢,否则它始终会在 5 秒后触发。请参阅下面的工作解决方案。
2021-03-30 18:06:58
我看到一些评论,doneTyping在示例中,回调函数立即运行。这通常是由于意外包含()在函数名称之后造成的请注意,应改为setTimeout(doneTyping,setTimeout(doneTyping(),
2021-03-30 18:06:58
@Jessica 要使用粘贴,您必须像这样添加“粘贴”事件: on('keyup paste',
2021-04-05 18:06:58
谢谢 :) 我开始输入我对这个问题的评论并意识到我有一个不错的主意。
2021-04-08 18:06:58

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

因为 TypingTimer 偶尔会设置多次(在为快速打字机等触发 keydown 之前按下 keyup 两次),所以它不能正确清除。

下面的解决方案解决了这个问题,并会在完成 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
}

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

该解决方案确实使用了 ES6,但这里没有必要。只需将letwithvar和箭头函数替换为常规函数即可。

对我来说,它立即调用该函数:/ 不是在 5 秒之后,我尝试增加时间,但同样的事情发生了
2021-03-13 18:06:58
我认为我们还应该考虑用户简单地将字符串粘贴到字段中的情况。
2021-03-16 18:06:58
为什么不使用 $(this).val()?
2021-03-24 18:06:58
$('#myInput').on('input', function() {如果您希望它与复制和粘贴一起使用,请使用如果输入为空,我看不到检查的重点。假设他想删除他输入的内容,这将无法进行 ajax 调用。
2021-03-30 18:06:58
好吧,即使输入为空,仍然调用该函数可能很有用。如果您想在输入再次为空白时清除某些搜索结果(例如)怎么办?
2021-04-03 18:06:58

它只是带有underscore.js去抖动功能的一行

$('#my-input-box').keyup(_.debounce(doSomething , 500));

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

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

@Paul 我同意,如果您为其他目的加载库,使用通用代码很好而且实际上是有益的。但是为了一行而加载 K 的代码效率不高。尤其是随着移动平台的无限数据越来越少。许多欧元区也通过数据支付互联网费用。所以在合理的情况下注意膨胀是件好事。
2021-03-12 18:06:58
@Wolfie,我同意你关于代码膨胀的看法,但 Underscore 和 Lodash 是NPM最依赖的两个实用程序,所以这对许多人来说可能是一种单行解决方案。
2021-03-15 18:06:58
令我惊讶的是人们如何吹捧“一行代码”至关重要。伟大的。一行需要加载 1.1k JS 文件的代码。我没有贬低这个,因为这是一个解决方案。但是单行大胆的事情让我感到厌烦并导致代码膨胀。
2021-03-16 18:06:58
如果你需要,你可以直接获得 debouce() 函数,npmjs.com/package/debounce效果很好。
2021-03-18 18:06:58
2021-03-22 18:06:58

是的,您可以在每个按键事件上设置 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
});

希望这可以帮助,

马可

我不会推荐这个。每次按下一个键,代码都会触发一个 API 请求然后,如果按下另一个键,它会取消请求。尽管此解决方案可防止在用户键入时触发 AJAX 回调,但它仍会向服务器发送请求。
2021-03-12 18:06:58
@JohnSmith,我不同意首先清除计时器可能更好,然后检查 xhr 是否为空或您的条件是什么,最后使用 ajax 调用运行计时器
2021-03-21 18:06:58
ixg,不,这不会。他使用的 clearTimeout 函数会清除之前的 Timeout 事件,从而调用 API 调用。
2021-03-23 18:06:58

迟到的答案,但我添加它是因为它是 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))
为什么这在事件侦听器之外不起作用?例如,如果我运行debounce(() => {alert("test")}, 1000),并且我没有在 1000 毫秒内再次运行它,它不应该运行回调和警报测试吗?
2021-03-17 18:06:58
编辑以进一步删除不需要的变量 - 可以this通过传递正常而不是箭头函数来避免必须封装setTimeout()
2021-03-25 18:06:58
我如何在事件处理函数中获取事件?
2021-03-25 18:06:58
这真的应该是今年的最佳答案
2021-03-27 18:06:58