Làm thế nào để kích hoạt một sự kiện trong văn bản đầu vào sau khi tôi ngừng nhập / viết?


84

Tôi muốn kích hoạt một sự kiện ngay sau khi tôi ngừng nhập (không phải khi đang nhập) các ký tự trong hộp văn bản đầu vào của mình.

Tôi đã thử với:

$('input#username').keypress(function() {
    var _this = $(this); // copy of this object for further usage

    setTimeout(function() {
        $.post('/ajax/fetch', {
            type: 'username',
            value: _this.val()
        }, function(data) {
            if(!data.success) {
                // continue working
            } else {
                // throw an error
            }
        }, 'json');
    }, 3000);
});

Nhưng ví dụ này tạo ra thời gian chờ cho mỗi ký tự được nhập và tôi nhận được khoảng 20 yêu cầu AJAX nếu tôi nhập 20 ký tự.

Trong trò chơi này, tôi chứng minh vấn đề tương tự với một cảnh báo đơn giản thay vì AJAX.

Có giải pháp nào cho việc này hay tôi chỉ đang sử dụng một cách tiếp cận tồi cho việc này?


1
Tôi e rằng javascript không cung cấp sự kiện cho phép bạn được thông báo khi người dùng ngừng nhập vào trường nhập. Tại sao bạn cần điều đó?
Darin Dimitrov

3
không phải là nó rõ ràng từ ví dụ? Tôi muốn kích hoạt một sự kiện "khi người dùng cuối dừng gõ vào nó", thay vì gửi 20 yêu cầu

1
Không có cách nào để biết khi nào người dùng thực sự nhập xong trừ khi họ gửi hoặc thay đổi các trường theo cách thủ công. Làm cách nào để biết người dùng có tạm dừng giữa câu và đợi 5 phút trước khi nhập thêm? Một giải pháp khả thi là sử dụng .blur () và gửi khi tiêu điểm người dùng rời khỏi trường.
Kevin M

14
Các ý kiến ​​trên là ngớ ngẩn. Đây là một trường hợp sử dụng phổ biến: Tôi muốn một sự kiện khi người dùng hoàn tất việc thay đổi kích thước cửa sổ của họ, thu phóng bản đồ, kéo, nhập ... về cơ bản, bất kỳ hành động liên tục nào của người dùng đều cần được chuyển sang vũ trụ kỹ thuật số của chúng ta. Ngay cả một lần nhấn phím duy nhất cũng gặp phải vấn đề này: khi bạn nhấn một phím, nó thực sự "nảy", tạo ra không chỉ 1 sự kiện nhấn phím mà còn nhiều sự kiện. Phần cứng hoặc hệ điều hành của máy tính của bạn loại bỏ các sự kiện bổ sung này và đó là lý do tại sao chúng ta có ảo tưởng về các sự kiện tổ hợp phím rời rạc. Điều này được gọi là "gỡ lỗi", và đây là những gì OP cần.
Ziggy

cảnh báo cho người dùng phản ứng: stackoverflow.com/a/28046731/57883
Maslow

Câu trả lời:


172

Bạn sẽ phải sử dụng setTimeout(giống như bạn đang sử dụng ) nhưng cũng lưu trữ tham chiếu để bạn có thể tiếp tục đặt lại giới hạn. Cái gì đó như:

//
// $('#element').donetyping(callback[, timeout=1000])
// Fires callback when a user has finished typing. This is determined by the time elapsed
// since the last keystroke and timeout parameter or the blur event--whichever comes first.
//   @callback: function to be called when even triggers
//   @timeout:  (default=1000) timeout, in ms, to to wait before triggering event if not
//              caused by blur.
// Requires jQuery 1.7+
//
;(function($){
    $.fn.extend({
        donetyping: function(callback,timeout){
            timeout = timeout || 1e3; // 1 second default timeout
            var timeoutReference,
                doneTyping = function(el){
                    if (!timeoutReference) return;
                    timeoutReference = null;
                    callback.call(el);
                };
            return this.each(function(i,el){
                var $el = $(el);
                // Chrome Fix (Use keyup over keypress to detect backspace)
                // thank you @palerdot
                $el.is(':input') && $el.on('keyup keypress paste',function(e){
                    // This catches the backspace button in chrome, but also prevents
                    // the event from triggering too preemptively. Without this line,
                    // using tab/shift+tab will make the focused element fire the callback.
                    if (e.type=='keyup' && e.keyCode!=8) return;
                    
                    // Check if timeout has been set. If it has, "reset" the clock and
                    // start over again.
                    if (timeoutReference) clearTimeout(timeoutReference);
                    timeoutReference = setTimeout(function(){
                        // if we made it here, our timeout has elapsed. Fire the
                        // callback
                        doneTyping(el);
                    }, timeout);
                }).on('blur',function(){
                    // If we can, fire the event since we're leaving the field
                    doneTyping(el);
                });
            });
        }
    });
})(jQuery);

$('#example').donetyping(function(){
  $('#example-output').text('Event last fired @ ' + (new Date().toUTCString()));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<input type="text" id="example" />
<p id="example-output">Nothing yet</p>

Điều đó sẽ thực thi khi:

  1. Đã hết thời gian chờ, hoặc
  2. Người dùng đã chuyển trường ( blursự kiện)

(Bất cứ thứ gì đến trước)


1
Vâng điều này tiết kiệm đêm của tôi. Cảm ơn
newbie

2
@Brad: Giải pháp jquery này hoạt động tốt ngoại trừ phím xóa lùi được nhập trong hộp nhập liệu không được phát hiện trong chrome mới nhất (38.0.2125.111). Chỉ thay đổi nó để keyuphoạt động. Bạn có thể muốn kiểm tra điều này và sửa đổi mã một cách thích hợp.
palerdot

1
@palerdot: Thật tốt khi biết, cảm ơn bạn. Tôi sẽ xem xét nó và đăng lại bất kỳ thay đổi nào.
Brad Christie

3
Cảm ơn vì plugin này - hoạt động tuyệt vời. Tôi phải thực hiện một điều chỉnh, bởi vì nó sẽ không hoạt động khi ai đó dán một thứ gì đó vào trường đầu vào. Tôi đã chỉnh sửa dòng sau để bao gồm paste -$el.is(':input') && $el.on('keyup keypress paste',function(e){
Matt

1
@ Sangar82: nên bây giờ (mặc dù tôi là một chút bối rối, ctrl + v nên được chụp bởi bấm phím - Trừ khi bạn đang phải cấp nhấp chuột> dán?
Brad Christie

71

GIẢI PHÁP:

Đây là giải pháp. Thực thi một chức năng sau khi người dùng đã ngừng nhập trong một khoảng thời gian cụ thể:

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

Sử dụng

$('input').keyup(function() {
  delay(function(){
    alert('Hi, func called');
  }, 1000 );
});

1
user1386320 - Kiểm tra giải pháp này Tôi gặp sự cố tương tự và tôi đã làm việc. Bạn sẽ thêm mã của mình vào vị trí của alert ().
Ata ul Mustafa

Cảm ơn. Hoạt động tốt.
user1919

2
Tôi có thể thêm N + Up phiếu bầu không? Giải pháp này tuyệt vời, ngắn gọn và trang nhã bằng cách sử dụng JavaScript Closures.
Matteo Conta

1
@MatteoConta, Cảm ơn bạn :)
Ata ul Mustafa

1
Tôi không muốn đưa underscore.js vào trang của mình chỉ vì điều này. Giải pháp của bạn hoạt động hoàn hảo! Cảm ơn
Skoempie 23/02

17

Bạn có thể sử dụng underscore.js "debounce"

$('input#username').keypress( _.debounce( function(){<your ajax call here>}, 500 ) );

Điều này có nghĩa là lệnh gọi hàm của bạn sẽ thực hiện sau 500 mili giây nhấn phím. Nhưng nếu bạn nhấn một phím khác (sự kiện nhấn phím khác được kích hoạt) trước 500ms, việc thực thi chức năng trước đó sẽ bị bỏ qua (đã gỡ lỗi) và chức năng mới sẽ thực thi sau một bộ đếm thời gian 500ms mới.

Để biết thêm thông tin, việc sử dụng _.debounce (func, timer, true ) có nghĩa là hàm đầu tiên sẽ thực thi và tất cả các sự kiện nhấn phím khác trong khoảng thời gian 500ms tiếp theo sẽ bị bỏ qua.


Rất hữu ích và ngắn gọn nếu bạn đã gạch dưới dưới dạng lib.
Francesco Pasa

10

Bạn cần debounce!

Đây là một plugin jQuery và đây là tất cả những gì bạn cần biết về debounce . Nếu bạn đang đến đây từ Google và Underscore đã tìm thấy đường vào JSoup của ứng dụng của bạn, thì nó đã bị loại bỏ ngay !


6

dung dịch làm sạch:

$.fn.donetyping = function(callback, delay){
  delay || (delay = 1000);
  var timeoutReference;
  var doneTyping = function(elt){
    if (!timeoutReference) return;
    timeoutReference = null;
    callback(elt);
  };

  this.each(function(){
    var self = $(this);
    self.on('keyup',function(){
      if(timeoutReference) clearTimeout(timeoutReference);
      timeoutReference = setTimeout(function(){
        doneTyping(self);
      }, delay);
    }).on('blur',function(){
      doneTyping(self);
    });
  });

  return this;
};

5

Bạn nên gán setTimeoutcho một biến và sử dụng clearTimeoutđể xóa nó khi nhấn phím.

var timer = '';

$('input#username').keypress(function() {
  clearTimeout(timer);
  timer = setTimeout(function() {
    //Your code here
  }, 3000); //Waits for 3 seconds after last keypress to execute the above lines of code
});

Vĩ cầm

Hi vọng điêu nay co ich.


3

Có một số plugin đơn giản mà tôi đã thực hiện làm được điều đó. Nó yêu cầu mã ít hơn nhiều so với các giải pháp được đề xuất và nó rất nhẹ (~ 0,6kb)

Đầu tiên bạn tạo Bidđối tượng hơn có thể bumpedbất cứ lúc nào. Mỗi lần tăng sẽ trì hoãn việc kích hoạt gọi lại Giá thầu trong khoảng thời gian nhất định tiếp theo.

var searchBid = new Bid(function(inputValue){
    //your action when user will stop writing for 200ms. 
    yourSpecialAction(inputValue);
}, 200); //we set delay time of every bump to 200ms

Khi Bidđối tượng đã sẵn sàng, chúng ta cần bumpnó bằng cách nào đó. Hãy đính kèm va chạm với keyup event.

$("input").keyup(function(){
    searchBid.bump( $(this).val() ); //parameters passed to bump will be accessable in Bid callback
});

Điều gì xảy ra ở đây là:

Mỗi khi người dùng nhấn phím, giá thầu bị 'trì hoãn' (tăng) trong 200 mili giây tiếp theo. Nếu 200ms trôi qua mà không bị 'va chạm' lần nữa, thì lệnh gọi lại sẽ được kích hoạt.

Ngoài ra, bạn có 2 chức năng bổ sung để dừng giá thầu (ví dụ: nếu người dùng nhấn esc hoặc nhấp vào đầu vào bên ngoài) và để hoàn tất và kích hoạt lệnh gọi lại ngay lập tức (ví dụ: khi người dùng nhấn phím enter):

searchBid.stop();
searchBid.finish(valueToPass);

1

Tôi đã tìm kiếm một mã HTML / JS đơn giản và tôi không tìm thấy bất kỳ mã nào. Sau đó, tôi đã viết mã bên dưới bằng cách sử dụng onkeyup="DelayedSubmission()".

<!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>

0

tại sao phải làm nhiều như vậy khi bạn chỉ muốn đặt lại đồng hồ?

var clockResetIndex = 0 ;
// this is the input we are tracking
var tarGetInput = $('input#username');

tarGetInput.on( 'keyup keypress paste' , ()=>{
    // reset any privious clock:
    if (clockResetIndex !== 0) clearTimeout(clockResetIndex);

    // set a new clock ( timeout )
    clockResetIndex = setTimeout(() => {
        // your code goes here :
        console.log( new Date() , tarGetInput.val())
    }, 1000);
});

nếu bạn đang làm việc trên wordpress, thì bạn cần phải bọc tất cả mã này bên trong một khối jQuery:

jQuery(document).ready(($) => {
    /**
     * @name 'navSearch' 
     * @version 1.0
     * Created on: 2018-08-28 17:59:31
     * GMT+0530 (India Standard Time)
     * @author : ...
     * @description ....
     */
        var clockResetIndex = 0 ;
        // this is the input we are tracking
        var tarGetInput = $('input#username');

        tarGetInput.on( 'keyup keypress paste' , ()=>{
            // reset any privious clock:
            if (clockResetIndex !== 0) clearTimeout(clockResetIndex);

            // set a new clock ( timeout )
            clockResetIndex = setTimeout(() => {
                // your code goes here :
                console.log( new Date() , tarGetInput.val())
            }, 1000);
        });
});

nếu bạn muốn mở rộng jquery và muốn sử dụng phương pháp này trong nhiều phần tử đầu vào, thì câu trả lời được chấp thuận là câu trả lời bạn đang tìm kiếm.
insCode

0

Sử dụng thuộc tính onkeyup = "myFunction ()" trong <input>html của bạn.


-1

Theo suy nghĩ của tôi, người dùng ngừng viết khi anh ta không tập trung vào đầu vào đó. Đối với điều này, bạn có một chức năng gọi là "làm mờ" có chức năng như


4
Sai lầm! mờ là một sự kiện khi tiêu điểm bị mất trên một trường nhập cụ thể. điều tôi cần là xác định thời điểm bàn phím không được sử dụng trong trường mà tôi đang cố gắng kích hoạt một sự kiện.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.