How to delay the .keyup() handler until the user stops typing?

前端 未结 27 2576
半阙折子戏
半阙折子戏 2020-11-21 23:32

I’ve got a search field. Right now it searches for every keyup. So if someone types “Windows”, it will make a search with AJAX for every keyup: “W”, “Wi”, “Win”, “Wind”, “Wi

27条回答
  •  北恋
    北恋 (楼主)
    2020-11-22 00:00

    This is a solution along the lines of CMS's, but solves a few key issues for me:

    • Supports multiple inputs, delays can run concurrently.
    • Ignores key events that didn't changed the value (like Ctrl, Alt+Tab).
    • Solves a race condition (when the callback is executed and the value already changed).
    var delay = (function() {
        var timer = {}
          , values = {}
        return function(el) {
            var id = el.form.id + '.' + el.name
            return {
                enqueue: function(ms, cb) {
                    if (values[id] == el.value) return
                    if (!el.value) return
                    var original = values[id] = el.value
                    clearTimeout(timer[id])
                    timer[id] = setTimeout(function() {
                        if (original != el.value) return // solves race condition
                        cb.apply(el)
                    }, ms)
                }
            }
        }
    }())
    

    Usage:

    signup.key.addEventListener('keyup', function() {
        delay(this).enqueue(300, function() {
            console.log(this.value)
        })
    })
    

    The code is written in a style I enjoy, you may need to add a bunch of semicolons.

    Things to keep in mind:

    • A unique id is generated based on the form id and input name, so they must be defined and unique, or you could adjust it to your situation.
    • delay returns an object that's easy to extend for your own needs.
    • The original element used for delay is bound to the callback, so this works as expected (like in the example).
    • Empty value is ignored in the second validation.
    • Watch out for enqueue, it expects milliseconds first, I prefer that, but you may want to switch the parameters to match setTimeout.

    The solution I use adds another level of complexity, allowing you to cancel execution, for example, but this is a good base to build on.

提交回复
热议问题