簡體   English   中英

當用戶完成鍵入而不是按鍵時運行 javascript function?

[英]Run javascript function when user finishes typing instead of on key up?

當用戶在文本框中輸入完畢時,我想觸發 ajax 請求。 我不希望它在每次用戶鍵入字母時運行 function,因為這會導致很多 ajax 請求,但是我也不希望他們必須按下回車按鈕。

有沒有一種方法可以檢測用戶何時完成輸入,然后執行 ajax 請求?

在這里使用 jQuery!

所以,我猜想完成打字意味着你只是停下來一會兒,比如 5 秒。 因此,考慮到這一點,讓我們在用戶釋放一個鍵時啟動一個計時器,並在他們按下一個鍵時清除它。 我決定有問題的輸入將是#myInput。

做幾個假設...

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 5000;  //time in ms, 5 seconds 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
}

上面選擇的答案不起作用。

因為 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,但這里沒有必要。 只需將let替換為var並將箭頭函數替換為常規函數即可。

這只是帶有underscore.js debounce 功能的一行

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

這基本上是在我停止輸入 500 毫秒后表示doSomething

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

遲到的答案,但我添加它是因為它是 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))

是的,您可以在每個觸發 ajax 請求的按鍵事件上設置 2 秒的超時時間。 您還可以存儲 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
});

希望這可以幫助,

馬爾科

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/

前 2 個答案對我都不起作用。 所以,這是我的解決方案:

var timeout = null;

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

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

修改接受的答案以處理其他情況,例如粘貼:

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

聲明以下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);
});    

我喜歡超現實夢的回答,但我發現我的“doneTyping”功能會在每次按鍵時觸發,即如果你真的很快輸入“Hello”; 當您停止輸入時,該函數不會只觸發一次,而是會觸發 5 次。

問題是 javascript setTimeout 函數似乎不會覆蓋或終止已設置的任何舊超時,但如果您自己執行它,它會起作用! 因此,如果設置了 typingTimer,我只是在 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
}

注意,我本來希望將其添加為對超現實夢的回答的評論,但我是新用戶,沒有足夠的聲譽。 對不起!

我認為在這種情況下不需要 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 的第一次回復,所以我希望有一天能對某人有所幫助:)

我正在我的列表中實現搜索,並且需要它基於 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

您會注意到在實現此功能時無需使用任何計時器。

同意@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);
});

我覺得input事件的解決方案有點簡單:

var typingTimer;
var doneTypingInterval = 500;

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

function doneTyping () {
    // code here
}

好吧,嚴格來說不是,因為計算機無法猜測用戶何時完成輸入。 您當然可以在按鍵時觸發計時器,並在每次后續按鍵時將其重置。 如果計時器到期,則用戶在計時器持續時間內沒有輸入 - 你可以稱之為“完成輸入”。

如果您希望用戶在鍵入時暫停,則無法知道他們何時完成。

(當然,除非您可以從數據中看出它們何時完成)

我只是想出了一個簡單的代碼來等待用戶完成輸入:

步驟 1. 將超時設置為空,然后在用戶鍵入時清除當前超時。

步驟 2.trigger 在觸發 keyup 事件之前清除變量定義的超時。

步驟 3.define timeout 到上面聲明的變量;

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

 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) })
 <textarea id='inText'>edit this and...</textarea> <pre id='outText'>see the results after you stop typing for one second</pre>

這是我寫的一個簡單的 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>

為什么不直接使用 onfocusout?

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

如果它是一個表單,他們將始終離開每個輸入字段的焦點,以便單擊提交按鈕,這樣您就知道在調用其 onfocusout 事件處理程序時不會錯過任何輸入。

您可以使用 onblur 事件來檢測文本框何時失去焦點: https ://developer.mozilla.org/en/DOM/element.onblur

這與“停止輸入”不同,如果您關心用戶輸入一堆東西然后坐在那里文本框仍然聚焦的情況。

為此,我建議將 setTimeout 綁定到 onclick 事件,並假設在 x 時間后沒有擊鍵,用戶已停止輸入。

每頁多個計時器

所有其他答案僅適用於一個控件(包括我的其他答案)。 如果每個頁面有多個控件(例如在購物車中) ,則只有最后一個用戶輸入內容的控件才會被調用 就我而言,這當然不是所希望的行為——每個控件都應該有自己的計時器。

為了解決這個問題,您只需將一個 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);

如果用戶有必要離開現場,我們可以在 Javascript 中使用“onBlur”而不是 Onchange

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

如果沒有必要設置計時器將是一個不錯的選擇。

如果您正在尋找特定長度(例如郵政編碼字段):

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

不確定我的需求是否有點奇怪,但我需要類似的東西,這就是我最終使用的:

$('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 秒內無操作)或轉到另一個字段(從元素中模糊)時,哪個會更新

如果您需要等到用戶完成輸入,請使用以下簡單操作:

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

使用 ajax 調用的完整示例 - 這適用於我的尋呼機 - 每個列表的項目計數:

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

一旦您檢測到文本框上的焦點,在按鍵上進行超時檢查,並在每次觸發時重置它。

超時完成后,執行您的 ajax 請求。

簡單易懂。

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

用於將參數與 ES6 語法一起傳遞給您的函數。

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

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

如果有人在尋找 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();
        });
    };
}]);

你們聽說過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);
})

我需要我的運行特定控件,這對我有用:

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

$('#txtFilterClientCode').keyup(debounce(function () {
            console.log("Test");
        }, 1000));

這是一個解決方案,它在 1 秒不輸入后觸發,但在輸入為空白時也會立即觸發。 這在用戶刪除輸入查詢后清除搜索結果時很有用。 該解決方案還支持復制粘貼到搜索框中。 $(() => { ... }); 用簡單的 Jquery 術語包裝代碼的頂部僅意味着“在加載頁面時執行此操作”。

var searchTimer;
var searchInterval = 1000;

$(() => {
    $('#search-box').on('input', (event) => {
        clearTimeout(searchTimer);
        searchTimer = setTimeout(() => {
            searchContacts(event.target.value);
        }, (event.target.value.length > 0) ? searchInterval : 0);
    });
});

function searchContacts(val) {
    console.log('searching: ' + val);
}

對於 alpine.js 用戶 <input @input.debounce.500ms="fn()">

哇,即使是3條評論也很正確!

  1. 空輸入不是跳過函數調用的原因,例如我在重定向之前從 url 中刪除了浪費參數

  2. .on ('input', function() { ... }); 應該用於觸發keyuppastechange事件

  3. 絕對必須使用.val().value

  4. 您可以在事件函數中使用$(this)而不是#id來處理多個輸入

  5. (我的決定)我使用匿名函數而不是setTimeout中的doneTyping從 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);      
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM