How to implement debounce in Vue2?

前端 未结 13 593
梦谈多话
梦谈多话 2020-11-27 11:08

I have a simple input box in a Vue template and I would like to use debounce more or less like this:



        
相关标签:
13条回答
  • 2020-11-27 11:17

    In case you need to apply a dynamic delay with the lodash's debounce function:

    props: {
      delay: String
    },
    
    data: () => ({
      search: null
    }),
    
    created () {
         this.valueChanged = debounce(function (event) {
          // Here you have access to `this`
          this.makeAPIrequest(event.target.value)
        }.bind(this), this.delay)
    
    },
    
    methods: {
      makeAPIrequest (newVal) {
        // ...
      }
    }
    

    And the template:

    <template>
      //...
    
       <input type="text" v-model="search" @input="valueChanged" />
    
      //...
    </template>
    

    NOTE: in the example above I made an example of search input which can call the API with a custom delay which is provided in props

    0 讨论(0)
  • 2020-11-27 11:17

    If you could move the execution of the debounce function into some class method you could use a decorator from the utils-decorators lib (npm install --save utils-decorators):

    import {debounce} from 'utils-decorators';
    
    class SomeService {
    
      @debounce(500)
      getData(params) {
      }
    }
    
    0 讨论(0)
  • 2020-11-27 11:21

    Very simple without lodash

      handleScroll: function() {
        if (this.timeout) 
          clearTimeout(this.timeout); 
    
        this.timeout = setTimeout(() => {
          // your action
        }, 200); // delay
      }
    
    0 讨论(0)
  • 2020-11-27 11:22

    updated in 2020

    Option 1: Re-usable, no deps

    (Recommended if needed more than once in your project)

    helpers.js

    export function debounce (fn, delay) {
      var timeoutID = null
      return function () {
        clearTimeout(timeoutID)
        var args = arguments
        var that = this
        timeoutID = setTimeout(function () {
          fn.apply(that, args)
        }, delay)
      }
    }
    

    Component.vue

    <script>
      import {debounce} from './helpers'
    
      export default {
        data () {
          return {
            input: '',
            debouncedInput: ''
          }
        },
        watch: {
          input: debounce(function (newVal) {
            this.debouncedInput = newVal
          }, 500)
        }
      }
    </script>
    

    Codepen


    Option 2: In-component, also no deps

    (Recommended if using once or in small project)

    Component.vue

    <template>
        <input type="text" v-model="input" />
    </template>
    
    <script>
      export default {
        data: {
          debouncedInput: ''
        },
        computed: {
         input: {
            get() {
              return this.debouncedInput
            },
            set(val) {
              if (this.timeout) clearTimeout(this.timeout)
              this.timeout = setTimeout(() => {
                this.debouncedInput = val
              }, 300)
            }
          }
        }
      }
    </script>
    

    Codepen

    0 讨论(0)
  • 2020-11-27 11:24

    If you are using Vue you can also use v.model.lazy instead of debounce but remember v.model.lazy will not always work as Vue limits it for custom components.

    For custom components you should use :value along with @change.native

    <b-input :value="data" @change.native="data = $event.target.value" ></b-input>

    0 讨论(0)
  • 2020-11-27 11:25

    Please note that I posted this answer before the accepted answer. It's not correct. It's just a step forward from the solution in the question. I have edited the accepted question to show both the author's implementation and the final implementation I had used.


    Based on comments and the linked migration document, I've made a few changes to the code:

    In template:

    <input type="text" v-on:input="debounceInput" v-model="searchInput">
    

    In script:

    watch: {
      searchInput: function () {
        this.debounceInput();
      }
    },
    

    And the method that sets the filter key stays the same:

    methods: {
      debounceInput: _.debounce(function () {
        this.filterKey = this.searchInput;
      }, 500)
    }
    

    This looks like there is one less call (just the v-model, and not the v-on:input).

    0 讨论(0)
提交回复
热议问题