ค้นหาเว็บไซต์

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

บทความที่เกี่ยวข้อง