javascript - วิธีหน่วงเวลา handler ของ .keyup() จนกว่าผู้ใช้จะหยุดพิมพ์?
ฉันมีช่องค้นหา ตอนนี้มันจะค้นหาทุกครั้งที่กดแป้น ดังนั้นถ้ามีคนพิมพ์ "Windows " มันจะทำการค้นหาด้วย AJAX ทุกครั้งที่กดแป้น: "W ", "Wi ", "Win ", "Wind ", "Windo ", "Window ", "Windows ".
ฉันต้องการให้มีการหน่วงเวลา ดังนั้นมันจะค้นหาเฉพาะเมื่อผู้ใช้หยุดพิมพ์เป็นเวลา 200 มิลลิวินาที
ไม่มีตัวเลือกสำหรับสิ่งนี้ในฟังก์ชัน keyup และฉันได้ลองใช้ setTimeout แล้ว แต่ก็ไม่ได้ผล
ฉันจะทำอย่างนั้นได้อย่างไร?
คำตอบ #1
ฉันใช้ฟังก์ชันเล็ก ๆ นี้เพื่อวัตถุประสงค์เดียวกัน คือการเรียกใช้ฟังก์ชันหลังจากที่ผู้ใช้หยุดพิมพ์เป็นระยะเวลาที่กำหนดหรือในเหตุการณ์ที่เกิดบ่อย เช่น resize:
function delay(callback, ms) {
var timer = 0;
return function() {
var context = this, args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
callback.apply(context, args);
}, ms || 0);
};
}
// Example usage:
$('#input').keyup(delay(function (e) {
console.log('Time elapsed!', this.value);
}, 500));<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label for="input">Try it:
<input id="input" type="text" placeholder="Type something here..."/>
</label>วิธีการทำงาน:
ฟังก์ชัน delay จะคืนค่าฟังก์ชันที่ห่อหุ้มซึ่งจัดการตัวจับเวลาส่วนบุคคลภายใน ในแต่ละครั้งที่เรียกใช้งาน ตัวจับเวลาจะเริ่มใหม่ด้วยเวลาหน่วงที่กำหนด หากมีการเรียกใช้งานหลายครั้งก่อนเวลานี้ผ่าน ตัวจับเวลาจะเพียงรีเซ็ตและเริ่มใหม่อีกครั้ง
เมื่อเวลาตัวจับเวลาสิ้นสุดลง ฟังก์ชัน callback จะถูกเรียกใช้งาน โดยส่งบริบทและอาร์กิวเมนต์เดิม (ในตัวอย่างนี้ จะเป็นออบเจ็กต์เหตุการณ์ของ jQuery และองค์ประกอบ DOM เป็น this)
อัปเดต 2019-05-16
ฉันได้ทำการติดตั้งฟังก์ชันใหม่โดยใช้คุณสมบัติของ ES5 และ ES6 สำหรับสภาพแวดล้อมสมัยใหม่:
function delay(fn, ms) {
let timer = 0
return function(...args) {
clearTimeout(timer)
timer = setTimeout(fn.bind(this, ...args), ms || 0)
}
}
การใช้งานถูกครอบคลุมด้วยชุดของการทดสอบ
สำหรับสิ่งที่ซับซ้อนมากขึ้น ลองดูที่ปลั๊กอิน jQuery Typewatch
คำตอบ #2
หากคุณต้องการค้นหาหลังจากการพิมพ์เสร็จ ใช้ตัวแปรระดับโลกเพื่อเก็บค่า timeout ที่ส่งกลับจากการเรียกใช้ setTimout ของคุณ และยกเลิกมันด้วย clearTimeout หากยังไม่เกิดขึ้น เพื่อที่จะได้ไม่เรียกใช้งาน timeout ยกเว้นในเหตุการณ์ keyup ครั้งสุดท้าย
var globalTimeout = null;
$('#id').keyup(function(){
if(globalTimeout != null) clearTimeout(globalTimeout);
globalTimeout =setTimeout(SearchFunc,200);
}
function SearchFunc(){
globalTimeout = null;
//ajax code
}
หรือกับฟังก์ชันไม่ระบุชื่อ :
var globalTimeout = null;
$('#id').keyup(function() {
if (globalTimeout != null) {
clearTimeout(globalTimeout);
}
globalTimeout = setTimeout(function() {
globalTimeout = null;
//ajax code
}, 200);
}
คำตอบ #3
การปรับปรุงเล็กน้อยอีกอย่างในคำตอบของ CMS เพื่อให้สามารถกำหนดความล่าช้าแยกกันได้อย่างง่ายดาย คุณสามารถใช้สิ่งต่อไปนี้:
function makeDelay(ms) {
var timer = 0;
return function(callback){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
};
ถ้าคุณต้องการนำความล่าช้าเดียวกันกลับมาใช้ใหม่ ก็แค่ทำ
var delay = makeDelay(250);
$(selector1).on('keyup', function() {delay(someCallback);});
$(selector2).on('keyup', function() {delay(someCallback);});
ถ้าคุณต้องการความล่าช้าแยกกัน คุณสามารถทำได้
$(selector1).on('keyup', function() {makeDelay(250)(someCallback);});
$(selector2).on('keyup', function() {makeDelay(250)(someCallback);});
คำตอบ #4
คุณยังสามารถดูที่ underscore.js ซึ่งให้เมธอดยูทิลิตี้เช่น debounce:
var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);
คำตอบ #5
jQuery:
var timeout = null;
$('#input').keyup(function() {
clearTimeout(timeout);
timeout = setTimeout(() => {
console.log($(this).val());
}, 1000);
});<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<input type="text" id="input" placeholder="Type here..."/>จาวาสคริปต์บริสุทธิ์:
let input = document.getElementById('input');
let timeout = null;
input.addEventListener('keyup', function (e) {
clearTimeout(timeout);
timeout = setTimeout(function () {
console.log('Value:', input.value);
}, 1000);
});<input type="text" id="input" placeholder="Type here..."/>คำตอบ #6
คำอธิบาย
ใช้ตัวแปรเพื่อเก็บฟังก์ชัน timeout จากนั้นใช้ clearTimeout() เพื่อล้างตัวแปรนี้จากฟังก์ชัน timeout ที่กำลังทำงานอยู่ แล้วจากนั้นใช้ setTimeout() เพื่อกำหนดฟังก์ชัน timeout ที่กำลังทำงานอีกครั้ง เราเรียกใช้ clearTimeout() ก่อน เพราะถ้าผู้ใช้กำลังพิมพ์ "hello" เราต้องการให้ฟังก์ชันของเราทำงานทันทีหลังจากผู้ใช้กดปุ่ม "o" (และไม่ต้องทำงานหนึ่งครั้งต่อหนึ่งตัวอักษร)
ตัวอย่างการทำงาน
วิธีที่ง่ายมาก ออกแบบมาเพื่อติดตามการทำงานของฟังก์ชันหลังจากผู้ใช้พิมพ์เสร็จในช่องข้อความ...
$(document).ready(function(e) {
var timeout;
var delay = 2000; // 2 seconds
$('.text-input').keyup(function(e) {
$('#status').html("User started typing!");
if(timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(function() {
myFunction();
}, delay);
});
function myFunction() {
$('#status').html("Executing function for user!");
}
});<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Status: <span id="status">Default Status</span><br>
<textarea name="text-input" class="text-input"></textarea>คำตอบ #7
จากคำตอบของ CMS ฉันได้ทำสิ่งนี้ขึ้น:
วางโค้ดด้านล่างหลังจากการรวม jQuery :
/*
* delayKeyup
* http://code.azerti.net/javascript/jquery/delaykeyup.htm
* Inspired by CMS in this post : http://stackoverflow.com/questions/1909441/jquery-keyup-delay
* Written by Gaten
* Exemple : $("#input").delayKeyup(function(){ alert("5 secondes passed from the last event keyup."); }, 5000);
*/
(function ($) {
$.fn.delayKeyup = function(callback, ms){
var timer = 0;
$(this).keyup(function(){
clearTimeout (timer);
timer = setTimeout(callback, ms);
});
return $(this);
};
})(jQuery);
และก็ใช้แบบนี้ได้เลย :
$('#input').delayKeyup(function(){ alert("5 secondes passed from the last event keyup."); }, 5000);
ระวัง: ตัวแปร $ (นี้) ในฟังก์ชันที่ส่งเป็นพารามิเตอร์ไม่ตรงกับอินพุต
คำตอบ #8
หน่วงการเรียกฟังก์ชันหลายรายการโดยใช้ป้ายกำกับ
นี่คือวิธีแก้ปัญหาที่ฉันทำงานด้วย จะทำให้การดำเนินการกับฟังก์ชันใดๆ ที่คุณต้องการล่าช้า อาจเป็นคำค้นหาแบบคีย์ดาวน์ หรืออาจเป็นการคลิกอย่างรวดเร็วบนปุ่มก่อนหน้าหรือถัดไป (มิฉะนั้นจะส่งคำขอหลายรายการหากคลิกอย่างรวดเร็วอย่างต่อเนื่อง และจะไม่ถูกใช้เลย) สิ่งนี้ใช้ออบเจ็กต์ส่วนกลางที่จัดเก็บเวลาดำเนินการแต่ละครั้ง และเปรียบเทียบกับคำขอล่าสุด
ดังนั้นผลลัพธ์ก็คือเพียงการคลิก/การกระทำครั้งสุดท้ายเท่านั้นที่จะถูกเรียกใช้จริง เนื่องจากคำขอเหล่านั้นถูกเก็บไว้ในคิว ซึ่งหลังจาก X มิลลิวินาทีจะถูกเรียกใช้หากไม่มีคำขออื่นที่มีป้ายกำกับเดียวกันอยู่ในคิว!
function delay_method(label,callback,time){
if(typeof window.delayed_methods=="undefined"){window.delayed_methods={};}
delayed_methods[label]=Date.now();
var t=delayed_methods[label];
setTimeout(function(){ if(delayed_methods[label]!=t){return;}else{ delayed_methods[label]=""; callback();}}, time||500);
}
คุณสามารถตั้งเวลาหน่วงของคุณเองได้ (เป็นตัวเลือก ค่าเริ่มต้นคือ 500 มิลลิวินาที) และส่งอาร์กิวเมนต์ของฟังก์ชันของคุณในลักษณะ "คลอสเชอร์"
ตัวอย่างเช่น หากคุณต้องการเรียกฟังก์ชันด้านล่าง:
function send_ajax(id){console.log(id);}
เพื่อป้องกันการส่งคำขอ send_ajax หลายครั้ง คุณสามารถหน่วงเวลาพวกมัน โดยใช้:
delay_method( "check date", function(){ send_ajax(2); } ,600);คำขอทุกครั้งที่ใช้ป้ายกำกับ "ตรวจสอบวันที่" จะถูกเรียกใช้งานก็ต่อเมื่อไม่มีคำขออื่นใดเกิดขึ้นภายในกรอบเวลา 600 มิลลิวินาที ข้อโต้แย้งนี้เป็นทางเลือก
ความเป็นอิสระของป้ายกำกับ (เรียกฟังก์ชันเป้าหมายเดียวกัน) แต่รันทั้งสอง:
delay_method("check date parallel", function(){send_ajax(2);});
delay_method("check date", function(){send_ajax(2);});
ส่งผลให้เรียกฟังก์ชันเดียวกัน แต่หน่วงเวลาอย่างอิสระเนื่องจากป้ายกำกับของพวกมันต่างกัน
คำตอบ #9
ถ้ามีคนต้องการเลื่อนฟังก์ชันเดียวกัน และไม่มีตัวแปรภายนอก เขาสามารถใช้สคริปต์ถัดไปได้:
function MyFunction() {
//Delaying the function execute
if (this.timer) {
window.clearTimeout(this.timer);
}
this.timer = window.setTimeout(function() {
//Execute the function code here...
}, 500);
}
