Як викликати подію у введеному тексті після того, як я перестану друкувати / писати?


84

Я хочу ініціювати подію відразу після того, як я перестану вводити (не під час набору) символи у текстовому полі введення.

Я пробував із:

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

Але цей приклад видає тайм-аут для кожного набраного символу, і я отримую близько 20 запитів AJAX, якщо вводжу 20 символів.

У цій скрипці я демонструю ту саму проблему за допомогою простого попередження замість AJAX.

Чи є рішення для цього, або я просто використовую поганий підхід для цього?


1
Я боюся, що javascript не надає події, яка дозволила б отримувати сповіщення, коли користувач перестає вводити текст у поле введення. Навіщо це потрібно?
Дарін Димитров

3
хіба це не видно з прикладу? Я хочу ініціювати подію "коли кінцевий користувач перестане вводити текст", замість того, щоб відправляти 20 запитів

1
Неможливо визначити, коли користувач фактично набирає текст, якщо він вручну не надсилає або не змінює поля. Як дізнатися, чи користувач робить паузу в середині речення і чекає 5 хвилин, перш ніж вводити більше? Можливим рішенням було б використовувати .blur () і відправляти, коли фокус користувача залишає поле.
Kevin M

14
Коментарі вище - безглузді. Це типовий варіант використання: я хочу одну подію, коли користувач закінчує змінювати розмір вікна, масштабувати карту, перетягувати, друкувати ... в основному будь-яка безперервна дія з боку користувача повинна бути переведена в наш цифровий всесвіт. Навіть одне натискання клавіші страждає від цієї проблеми: коли ви натискаєте клавішу, вона насправді "відскакує", створюючи не просто 1 подію натискання клавіші, а багато. Апаратне забезпечення або ОС вашого комп’ютера видаляє ці зайві події, і тому у нас є ілюзія дискретних подій натискання клавіш. Це називається "зняттям", і це те, що потрібно ОП.
Ziggy

попередження для реагуючих користувачів: stackoverflow.com/a/28046731/57883
Маслоу

Відповіді:


172

Вам доведеться використовувати setTimeout(як ви), але також зберігати посилання, щоб ви могли продовжувати скидати ліміт. Щось на зразок:

//
// $('#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>

Це буде виконано, коли:

  1. Час очікування минув, або
  2. Користувач змінив поля ( blurподія)

(Що станеться раніше)


1
Так, це рятує мою ніч. Дякую
новачок

2
@Brad: Це рішення jquery працює нормально, за винятком того, що клавіша зворотного простору, введена у вікні введення, не виявлена ​​в останньому chrome (38.0.2125.111). keyupПрацює лише його зміна . Можливо, ви захочете перевірити це і відповідно змінити код.
palerdot

1
@palerdot: Добре знати, дякую. Я розгляну це і опублікую будь-які зміни.
Бред Крісті

3
Дякую за цей плагін - чудово працює. Мені довелося зробити одне коригування, оскільки це не спрацювало б, коли хтось щось вставляв у поле введення. Я відредагував наступний рядок, щоб включити paste -$el.is(':input') && $el.on('keyup keypress paste',function(e){
Метт

1
@ Sangar82: Чи слід зараз (хоча я трохи заплутаний, ctrl + v слід зафіксувати натисканням клавіші - якщо ви не клацаєте правою кнопкою миші-> вставляєте?)
Бред Крісті

71

РІШЕННЯ:

Ось рішення. Виконання функції після того, як користувач перестав вводити текст протягом певного періоду часу:

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

Використання

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

1
user1386320 - Перевірте це рішення. У мене схожа проблема, і я працюю. Ви додасте свій код замість сповіщення ().
Ata ul Mustafa

Дякую. Працює гарно.
user1919

2
Чи можу я додати N + голосів? Це рішення є блискучим, коротким та елегантним за допомогою JavaScript Closures.
Маттео Конта

1
@MatteoConta, дякую :)
Ata ul Mustafa

1
Я не хотів включати underscore.js на свою сторінку лише для цього. Ваше рішення працює ідеально! Дякую
Skoempie

17

Ви можете використовувати underscore.js "debounce"

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

Це означає, що виклик функції виконується після 500 мс натискання клавіші. Але якщо натиснути іншу клавішу (запускається інша подія натискання клавіші) до 500 мс, попереднє виконання функції буде проігноровано (розірвано), а нове виконане через новий таймер 500 мс.

Для отримання додаткової інформації використання _.debounce (func, timer, true ) означало б, що перша функція буде виконана, а всі інші події натискання клавіш з наступними таймерами 500 мс будуть проігноровані.


Дуже корисно і коротко, якщо ви вже підкреслюєте як підказку.
Франческо Паса

10

Вам потрібен розбір!

Ось плагін jQuery , і ось все, що вам потрібно знати про debounce . Якщо ви їдете сюди з Google і подчерка знайшов свій шлях в JSoup вашого застосування, він має брязкіт випікатися !


6

очищений розчин:

$.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

Ви повинні призначити setTimeoutзмінну і використовувати, clearTimeoutщоб очистити її при натисканні клавіші.

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

Скрипка

Сподіваюся, це допомагає.


3

Існує якийсь простий плагін, який я робив саме так. Він вимагає набагато менше коду, ніж пропоновані рішення, і він дуже легкий (~ 0,6 кб)

Спочатку ви створюєте Bidоб'єкт, ніж це може бути bumpedбудь-коли. Кожен удар буде затримувати зворотній виклик заявки на наступний заданий проміжок часу.

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

Коли Bidоб’єкт готовий, нам це потрібно bumpякось. Давайте прикріпимо натикання на keyup event.

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

Що тут відбувається:

Кожного разу, коли користувач натискає клавішу, ставка `` відкладається '' (зіштовхується) на наступні 200 мс. Якщо пройде 200 мс без повторного "зіткнення", зворотний дзвінок буде запущений.

Крім того, у вас є 2 додаткові функції для зупинки ставки (якщо користувач натиснув клавішу esc або натиснув зовнішній вхід, наприклад), а також для негайного завершення та запуску зворотного виклику (наприклад, коли користувач натискає клавішу Enter):

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

1

Я шукав простий код HTML / JS і не знайшов жодного. Потім я написав код нижче, використовуючи 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

навіщо так багато, коли ви просто хочете скинути годинник?

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

якщо ви працюєте над wordpress, то вам потрібно обернути весь цей код всередині блоку 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);
        });
});

якщо ви хочете розширити jquery і хочете використовувати цей метод у декількох елементах введення, тоді затверджена відповідь - це відповідь, яку ви шукаєте.
insCode


-1

На мою думку, користувач перестає писати, коли він не фокусується на цьому введенні. Для цього у вас є функція "розмиття", яка робить подібні речі


4
неправильно! розмиття - це подія, коли фокус втрачається на певному полі введення. мені потрібно визначити, коли клавіатура не використовується під тим полем, на якому я намагаюся викликати подію.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.