我想在用户在文本框中输入完内容后触发ajax请求。我不希望它在用户每次输入字母时都运行该函数,因为这会导致大量的ajax请求,但是我也不希望他们也必须按Enter键。

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

在这里使用jQuery!
Dave

评论

我认为您需要为我们定义“完成输入”。

@Surreal Dreams的答案可以满足您的大多数要求,但是,如果用户在指定的超时时间后再次开始键入,则会将多个请求发送到服务器。请参阅下面的答案,该答案将每个XHR请求存储在一个变量中,并在发出新请求之前将其取消。实际上,这就是Google在即时搜索中所做的。

所选答案有误,有以下几个原因:1.即使用户正在键入,它也会在5秒后触发。 2.不会等到用户按要求完成输入。 3.如上面@Marko所述,它将触发多个请求。请参阅下面我的更正答案。

那模糊呢?我猜想当输入元素失去焦点时,用户肯定已经完成了键入。

一个简单的谷歌搜索可以给你一个简单的答案:schier.co/blog/2014/12/08/…

#1 楼

因此,我猜想完成键入意味着您只需停顿一会儿,例如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
}


评论


谢谢:)我开始对问题发表评论,意识到我有一个不错的主意。

–超现实的梦想
2010-11-18 22:22

该答案无法正常运行,除非用户输入速度非常慢,否则它将始终在5秒钟后触发。请参阅下面的工作解决方案。

–进行中
2011年5月8日在10:07

如果您在此处遇到麻烦,因为计时器立即触发,请尝试在函数调用周围添加引号:setTimeout('functionToBeCalled',doneTypingInterval);

– Largo
2012年7月13日在10:08

我看到一些评论,其中示例中的回调函数doneTyping立即运行。这通常是由于在函数名称之后意外地包含()而导致的。请注意,它应读取setTimeout(doneTyping,而不是setTimeout(doneTyping()),

–安东尼·迪桑蒂(Anthony DiSanti)
15年6月19日在23:29

@Jessica要使用粘贴,您必须添加“ paste”事件,如下所示:on('keyup paste',

–谢尔盖
16年4月1日在13:17

#2 楼

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

,因为偶尔会多次设置打字计时器(两次按下快捷键之前会按下快捷键,以便快速打字机等),所以无法正确清除。

以下解决方案可以解决此问题,并会在完成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
}


与香草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,但此处没有必要。只需将let替换为var,并将箭头函数替换为常规函数即可。

评论


好吧,即使输入为空,仍然调用该函数可能很有用。如果您想清除某些搜索结果(例如),当输入再次为空白时该怎么办?

–rvighne
2014年2月5日,凌晨3:01

我认为我们还应该考虑用户仅将字段字符串粘贴到字段中的情况。

– Vishal Nair
2014年8月1日在9:49

使用$('#myInput')。on('input',function(){如果您希望此功能可用于复制和粘贴。如果输入为空,我看不到检查的要点。假设他要擦除他键入的内容将无法进行ajax调用。

–billynoah
2014年10月6日在5:07

为什么不使用$(this).val()?

– JoelFan
15年2月26日在23:20

对我来说,它立即调用该函数:/不是在5秒钟后,我尝试增加时间,但是发生了同样的事情

– Xsmael
18年5月8日在23:46

#3 楼

这只是使用underscore.js防反跳功能的一行:

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


这基本上说了我停止输入500毫秒后的声音。 :http://underscorejs.org/#debounce

评论


似乎也可用于jQuery:code.google.com/p/jquery-debounce和github.com/diaspora/jquery-debounce

– koppor
13年5月2日,11:37

人们称赞“一行代码”是至关重要的,这让我感到惊讶。大。一行代码,需要加载1.1k JS文件。我不会对此表示反对,因为这是一种解决方案。但是一行大胆的事情使我感到不安,并导致代码膨胀。

– Wolfie
16年5月20日在16:17

@Wolfie,我同意您对代码膨胀的看法,但是Underscore和Lodash是NPM上依赖的前两个实用程序,因此对于许多人来说,这可能是单行解决方案。

– Paul
16年5月28日在20:17

@Paul我同意,如果您出于其他目的加载库,则使用通用代码很好而且实际上是有益的。但是,为了一行的目的而加载K的代码效率不高。尤其是随着移动平台变得越来越少的无限数据。而且许多欧元区也通过数据为互联网付费。因此在合理的时候注意to肿是一件好事。

– Wolfie
16年6月3日在16:19

@Wolfie他确实给限定词加上下划线。

– wuliwong
17-10-10在19:40

#4 楼

是的,您可以为每个会触发Ajax请求的按键事件设置2秒的超时时间。您还可以存储XHR方法,并在随后的按键事件中中止该方法,从而节省更多带宽。这是我为我的自动完成脚本编写的内容。

评论


我不会推荐这个。每次按键,该代码都会触发API请求。然后,如果按下另一个键,则取消请求。即使此解决方案可以防止在用户键入时触发AJAX回调,但它仍会向服务器发出请求。

–lxg
17 Mar 27 '17 at 12:31

伊克斯,不,这不会。他使用的clearTimeout函数清除先前的Timeout事件,从而调用API调用。

–约翰·史密斯
18年3月30日在18:00

@JohnSmith,我不同意,最好先清除计时器,然后检查xhr是否为空或您的情况如何,最后通过ajax调用运行计时器

–luukvhoudt
18年5月11日在18:51

#5 楼

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


此处的完整示例:http://jsfiddle.net/ZYXp4/8/

评论


这对我有用,但是请记住,当用户跳出文本框时,您不会收到键入事件,因为该事件在那时已经失去了焦点。将其设置为keydown似乎可以解决问题。

–horatius83
2013年9月27日19:51

#6 楼

较晚的答案,但我要添加它,因为它是在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))
 


评论


这确实是当年给出的最佳答案

–黑暗河马
5月28日6:52

编辑以进一步删除不需要的变量-可以通过将常规函数(而非箭头函数)传递给setTimeout()来解决封装问题

– GreyedFox
7月30日13:46



#7 楼

前两个答案对我都不起作用。所以,这是我的解决方案:

var timeout = null;

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

    timeout = setTimeout(function() {
        //do stuff here
    }, 500);
});


#8 楼

我喜欢“超现实梦想”的答案,但是我发现我的“ doneTyping”功能会在每次按键时触发,即,如果您真正快速地键入“ Hello”;该函数将触发5次,而不是在您停止键入时仅触发一次。但是,如果您自己动手,它会起作用!因此,如果设置了typeTimer,我只是在setTimeout之前添加了clearTimeout调用。参见下文:

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


N.B.我本想将其添加为“超现实梦想”答案的注释,但我是新用户,并且信誉不足。抱歉!

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


#10 楼

声明以下delay函数:

var delay = (function () {
    var timer = 0;
    return function (callback, ms) {
        clearTimeout(timer);
        timer = setTimeout(callback, ms);
    };
})()


,然后使用它:

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


评论


您的解决方案太棒了,兄弟!

– DmitryBoyko
19年4月24日在7:22

@Developer非常感谢。我还添加了另一个答案来解决更复杂的情况(每页多个控件)。

–法比安·比格勒(Fabian Bigler)
19年4月26日在6:20

好的解决方案。我正在使用这个,但不是使用'input'事件来按下keydown

–布丁
19年8月21日在12:37

#11 楼

我认为在这种情况下,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)
    }

}


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

#12 楼

同意@going的答案。另一个适用于我的类似解决方案是以下解决方案。唯一的区别是我使用的是.on(“ input” ...)而不是keyup。这仅捕获输入中的更改。其他键(例如Ctrl,Shift等)将被忽略

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

//on input change, start the countdown

$('#myInput').on("input", function() {    
    clearTimeout(typingTimer);
    typingTimer = setTimeout(function(){
        // doSomething...
    }, doneTypingInterval);
});


#13 楼

好吧,严格来说,不能,因为计算机无法猜测用户何时完成输入。当然,您可以在启动按键时触发一个计时器,并在以后的每次按键启动时将其重置。如果计时器到期,则用户没有在计时器持续时间内键入内容-您可以将其称为“完成的键入内容”。

如果您希望用户在键入时进行暂停,则无法知道他们何时输入已经完成。

(除非您当然不能从数据中得知完成的时间)

#14 楼

我觉得input事件的解决方案有点简单:

 var typingTimer;
var doneTypingInterval = 500;

$("#myInput").on("input", function () {
    window.clearTimeout(typingTimer);
    typingTimer = window.setTimeout(doneTyping, doneTypingInterval);
});

function doneTyping () {
    // code here
}
 


#15 楼

我只是想出一个简单的代码来等待用户完成键入操作:

步骤1.将timeout设置为null,然后在用户键入时清除当前超时。

步骤2.在触发keyup事件之前将清除超时触发到变量定义。

步骤3.将超时定义为上面声明的变量;

<input type="text" id="input" placeholder="please type" style="padding-left:20px;"/>
<div class="data"></div>


javascript代码

var textInput = document.getElementById('input');
var textdata = document.querySelector('.data');
// Init a timeout variable to be used below
var timefired = null;

// Listen for keystroke events
// Init a timeout variable to be used below
var timefired = null;// Listen for keystroke events
textInput.onkeyup = function (event) {
clearTimeout(timefired);
timefired = setTimeout(function () {
    textdata.innerHTML = 'Input Value:'+ textInput.value;
  }, 600);
};


评论


这个问题已经被回答了……和这个很相似

– Mixone
18年1月13日在16:37

#16 楼

我正在列表中实施搜索,因此需要基于Ajax的搜索。这意味着在每次更改键时,都应更新并显示搜索结果。这导致发送到服务器的ajax调用太多,这不是一件好事。

经过一些工作,我制定了一种在用户停止键入时对服务器执行ping操作的方法。

此解决方案对我有用:

$(document).ready(function() {
    $('#yourtextfield').keyup(function() {
        s = $('#yourtextfield').val();
        setTimeout(function() { 
            if($('#yourtextfield').val() == s){ // Check the value searched is the latest one or not. This will help in making the ajax call work when client stops writing.
                $.ajax({
                    type: "POST",
                    url: "yoururl",
                    data: 'search=' + s,
                    cache: false,
                    beforeSend: function() {
                       // loading image
                    },
                    success: function(data) {
                        // Your response will come here
                    }
                })
            }
        }, 1000); // 1 sec delay to check.
    }); // End of  keyup function
}); // End of document.ready


您会注意到,实现此功能时无需使用任何计时器。

#17 楼

这是我写的一个简单的JS代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pt-br" lang="pt-br">
<head><title>Submit after typing finished</title>
<script language="javascript" type="text/javascript">
function DelayedSubmission() {
    var date = new Date();
    initial_time = date.getTime();
    if (typeof setInverval_Variable == 'undefined') {
            setInverval_Variable = setInterval(DelayedSubmission_Check, 50);
    } 
}
function DelayedSubmission_Check() {
    var date = new Date();
    check_time = date.getTime();
    var limit_ms=check_time-initial_time;
    if (limit_ms > 800) { //Change value in milliseconds
        alert("insert your function"); //Insert your function
        clearInterval(setInverval_Variable);
        delete setInverval_Variable;
    }
}

</script>
</head>
<body>

<input type="search" onkeyup="DelayedSubmission()" id="field_id" style="WIDTH: 100px; HEIGHT: 25px;" />

</body>
</html>


#18 楼

您可以使用onblur事件来检测文本框何时失去焦点:
https://developer.mozilla.org/en/DOM/element.onblur

与“停止”不同打字”,如果您关心的是用户键入一堆东西然后坐在那里仍使文本框仍处于焦点的情况。在没有按键的情况下经过x的时间后,用户已停止键入。

#19 楼

为什么不只使用onfocusout?

https://www.w3schools.com/jsreF/event_onfocusout.asp

如果是表单,它们将始终保留每个输入的焦点字段以单击“提交”按钮,以便您知道没有任何输入会错过调用其onfocusout事件处理程序的机会。

评论


当问到这个问题时(现在大约7年前),onfocusout的支持很差,而且onfocusout的效果也会有所不同。您将不得不等待用户将注意力集中在元素上,而使用超时/去抖动解决方案,它将在用户停止键入并且不需要用户切换焦点时立即触发。用例示例是那些注册表单之一,其中,当用户停止输入潜在的用户名时,表单字段右侧会出现一个选中标记或“ X”,表明该名称可用。

–David Zorychta
17年8月29日在2:21

如果搜索栏处于焦点位置,则无需走到外面,过一会儿,结果将直接显示出来,因为不再输入任何空缺

–P Satish Patro
19/12/7在6:32

#20 楼

每页多个计时器

所有其他答案仅适用于一个控件(包括我的其他答案)。
如果每页有多个控件(例如,在购物车中),则只有最后一个控件用户键入的内容将被调用。就我而言,这当然不是所希望的行为-每个控件都应具有自己的计时器。要解决此问题,只需将ID传递给函数并维护timeoutHandles字典,如下所示代码:

功能声明:

var delayUserInput = (function () {
    var timeoutHandles = {};    
    return function (id, callback, ms) {        
        if (timeoutHandles[id]) {
            clearTimeout(timeoutHandles[id]);
        }

        timeoutHandles[id] = setTimeout(callback, ms);             
    };
})();


功能用法:

  delayUserInput('yourID', function () {
     //do some stuff
  }, 1000);


#21 楼

如果用户有必要离开该字段,则可以在Javascript中使用“ onBlur”代替Onchange。

  <TextField id="outlined-basic"  variant="outlined" defaultValue={CardValue} onBlur={cardTitleFn} />


#22 楼

一旦检测到对文本框的关注,请在启动键上进行超时检查,并在每次触发时将其重置。

超时完成后,请执行ajax请求。

#23 楼

如果您要查找特定长度(例如邮政编码字段):

$("input").live("keyup", function( event ){
if(this.value.length == this.getAttribute('maxlength')) {
        //make ajax request here after.
    }
  });


评论


在发送ajax请求之前进行有限验证不是一个坏主意。

– chim
2015年10月12日在9:19

#24 楼

不知道我的需求是否有点奇怪,但是我需要与此类似的东西,这就是我最终使用的东西:

$('input.update').bind('sync', function() {
    clearTimeout($(this).data('timer'));            
    $.post($(this).attr('data-url'), {value: $(this).val()}, function(x) {
        if(x.success != true) {
            triggerError(x.message);    
        }
    }, 'json');
}).keyup(function() {
    clearTimeout($(this).data('timer'));
    var val = $.trim($(this).val());
    if(val) {
        var $this = $(this);
        var timer = setTimeout(function() {
            $this.trigger('sync');
        }, 2000);
        $(this).data('timer', timer);
    }
}).blur(function() {
    clearTimeout($(this).data('timer'));     
    $(this).trigger('sync');
});


我可以使用一些元素在我的应用程序中是这样的:

<input type="text" data-url="/controller/action/" class="update">


当用户“完成键入”(2秒钟无操作)或进入另一个字段(模糊不清)时,哪个更新元素)

#25 楼

如果您需要等到用户输入完毕,请使用以下简单命令:

$(document).on('change','#PageSize', function () {
    //Do something after new value in #PageSize       
});


用ajax调用的完整示例-适用于我的寻呼机-每个列表的项目计数: br />
$(document).ready(function () {
    $(document).on('change','#PageSize', function (e) {
        e.preventDefault();
        var page = 1;
        var pagesize = $("#PageSize").val();
        var q = $("#q").val();
        $.ajax({
            url: '@Url.Action("IndexAjax", "Materials", new { Area = "TenantManage" })',
            data: { q: q, pagesize: pagesize, page: page },
            type: 'post',
            datatype: "json",
            success: function (data) {
                $('#tablecontainer').html(data);
               // toastr.success('Pager has been changed', "Success!");
            },
            error: function (jqXHR, exception) {
                ShowErrorMessage(jqXHR, exception);
            }
        });  
    });
});    


#26 楼

简单易懂。

var mySearchTimeout;
$('#ctl00_mainContent_CaseSearch').keyup(function () {
   clearTimeout(mySearchTimeout);
   var filter = $(this).val();
   mySearchTimeout = setTimeout(function () { myAjaxCall(filter); }, 700);
   return true;
});


#27 楼

用于将参数和ES6语法一起传递给函数。

$(document).ready(() => {
    let timer = null;
     $('.classSelector').keydown(() => {
     clearTimeout(timer); 
     timer = setTimeout(() => foo('params'), 500);
  });
});

const foo = (params) => {
  console.log(`In foo ${params}`);
}


#28 楼

如果有人在寻找AngularJS解决方案,这不是一个直接的答案。我根据此处的常用解决方案编写了指令。
 app.directive("ngTypeEnds", ["$timeout", function ($timeout) {
    return function (scope, element, attrs) {
        var typingTimer;               
        element.bind("keyup", function (event) {
            if (typingTimer)
                $timeout.cancel(typingTimer);
            if (angular.element(element)[0].value) {
                typingTimer = $timeout(function () {
                    scope.$apply(function () {
                        scope.$eval(attrs.ngTypeEnds);
                    });
                }, 500);
            }
            event.preventDefault();
        });
    };
}]);


#29 楼

你们听说过javascript中的闭包吗?
非常简单明了,只需将当前输入值与setTimeOut函数关闭的旧值进行比较,就可以了。
let timer;
$('#myInput').on('keyup', function() {
  window.clearTimeout(timer);
  // here is the closures javascript magic happens.
  const value = $(this).val();
  timer = setTimeout(() => {
    if(value === $(this).val() && $(this).val()!== ''){
        alert($(this).val());
    }
  }, 500);
})


#30 楼

哇,连3条评论都非常正确!


空输入不是跳过函数调用的原因,例如重定向前我从网址中删除了浪费参数
必须使用.on ('input', function() { ... });触发keyuppastechange事件
必须使用.val().value
您可以在事件函数内部使用$(this)而不是#id使用多个输入
(我的决定)我使用匿名函数而不是doneTyping中的setTimeout从n.4轻松访问$(this),但是您需要像var $currentInput = $(this);这样先保存它

编辑我看到有些人不了解复制粘贴好的代码的方向。您在这里

var typingTimer;
//                  2
$("#myinput").on('input', function () {
    //             4     3
    var input = $(this).val();
    clearTimeout(typingTimer);
    //                           5
    typingTimer = setTimeout(function() {
        // do something with input
        alert(input);
    }, 5000);      
});


评论


这如何回答问题?

–托马斯·奥尔利塔(Thomas Orlita)
17年6月13日在7:12

@ThomasOrlita这个答案补充了3个最受好评的答案。看一看被接受的内容:1.它不支持粘贴,不使用它,依此类推。(我认为这很重要,但我不想迷失在大量评论中)

–vladkras
17年6月13日在16:37



这不能回答问题。如果您想评论另一个答案,则有一个评论系统(我现在正在使用它!)

– GreyedFox
19年9月2日在21:50