如何在Vue2中实现去抖?

时间:2017-02-13 08:51:02

标签: vue.js vuejs2 debouncing

我在Vue模板中有一个简单的输入框,我想或多或少地使用debounce:

<input type="text" v-model="filterKey" debounce="500">

debounce属性为deprecated in Vue 2。该建议仅说:“使用v-on:输入+第三方去抖功能”。

您如何正确实施?

我尝试使用 lodash v-on:input v-model 来实现它,但我想知道它是否是可以没有额外的变量。

在模板中:

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

在剧本中:

data: function () {
  return {
    searchInput: '',
    filterKey: ''
  }
},

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

稍后在computed道具中使用过滤器密钥。

15 个答案:

答案 0 :(得分:107)

我正在使用debounce NPM包,并按照以下方式实施:

<input @input="debounceInput">

methods: {
    debounceInput: debounce(function (e) {
      this.$store.dispatch('updateInput', e.target.value)
    }, config.debouncers.default)
}

使用lodash和问题中的示例,实现如下:

<input v-on:input="debounceInput">

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

答案 1 :(得分:35)

methods中分配去抖动可能会有麻烦。所以不要这样:

// Bad
methods: {
  foo: _.debounce(function(){}, 1000)
}

您可以尝试:

// Good
created () {
  this.foo = _.debounce(function(){}, 1000);
}

如果你有一个组件的多个实例,那就成了一个问题 - 类似于data应该是一个返回一个对象的函数的方式。如果它们应该独立行动,每个实例都需要自己的去抖功能。

以下是问题的一个示例:

&#13;
&#13;
Vue.component('counter', {
  template: '<div>{{ i }}</div>',
  data: function(){
    return { i: 0 };
  },
  methods: {
    // DON'T DO THIS
    increment: _.debounce(function(){
      this.i += 1;
    }, 1000)
  }
});


new Vue({
  el: '#app',
  mounted () {
    this.$refs.counter1.increment();
    this.$refs.counter2.increment();
  }
});
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>

<div id="app">
  <div>Both should change from 0 to 1:</div>
  <counter ref="counter1"></counter>
  <counter ref="counter2"></counter>
</div>
&#13;
&#13;
&#13;

答案 2 :(得分:7)

我遇到了同样的问题,并且没有插件就可以了。

由于<input v-model="xxxx">

完全相同
<input
   v-bind:value="xxxx"
   v-on:input="xxxx = $event.target.value"
>

(source)

我认为我可以在xxxx = $event.target.value的xxxx分配中设置一个反跳功能

像这样

<input
   v-bind:value="xxxx"
   v-on:input="debounceSearch($event.target.value)"
>

方法:

debounceSearch(val){
  if(search_timeout) clearTimeout(search_timeout);
  var that=this;
  search_timeout = setTimeout(function() {
    that.xxxx = val; 
  }, 400);
},

答案 3 :(得分:3)

  

请注意,我在接受的答案之前发布了这个答案。不是   正确。这只是从解决方案向前迈出的一步   题。我编辑了已接受的问题,以显示作者的实现和我使用过的最终实现。

根据评论和linked migration document,我对代码进行了一些更改:

在模板中:

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

在剧本中:

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

设置过滤器键的方法保持不变:

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

这看起来只有少一个电话(只有v-model,而不是v-on:input)。

答案 4 :(得分:2)

如果你需要一个非常简约的方法,我做了一个(最初从vuejs-tips分支,也支持IE),可以在这里找到:https://www.npmjs.com/package/v-debounce

用法:

<input v-model.lazy="term" v-debounce="delay" placeholder="Search for something" />

然后在你的组件中:

<script>
export default {
  name: 'example',
  data () {
    return {
      delay: 1000,
      term: '',
    }
  },
  watch: {
    term () {
      // Do something with search term after it debounced
      console.log(`Search term changed to ${this.term}`)
    }
  },
  directives: {
    debounce
  }
}
</script>

答案 5 :(得分:2)

非常简单,没有lodash

  handleScroll: function() {
   if (this.timeout) clearTimeout(this.timeout); 
     this.timeout = setTimeout(() => {
       // your action
     }, 200);
  }

答案 6 :(得分:1)

可重复使用,没有使用

helpers.js

module.exports = 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)
  }
}

.vue

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

(贷记tiny debounce

答案 7 :(得分:1)

要创建去抖动方法,您可以使用计算方法,这样它们就不会在组件的多个实例之间共享:

<template>
  <input @input="handleInputDebounced">
<template>

<script>
import debounce from 'lodash.debouce';

export default {
  props: {
    timeout: {
      type: Number,
      default: 200,
    },
  },
  methods: {
    handleInput(event) {
      // input handling logic
    },
  },
  computed: {
    handleInputDebounced() {
      return debounce(this.handleInput, this.timeout);
    },
  },
}
</script>

您也可以使用不受控制的 v-model

<template>
  <input v-model="debouncedModel">
<template>

<script>
import debounce from 'lodash.debouce';

export default {
  props: {
    value: String,
    timeout: {
      type: Number,
      default: 200,
    },
  },
  methods: {
    updateValue(value) {
      this.$emit('input', value);
    },
  },
  computed: {
    updateValueDebounced() {
      return debounce(this.updateValue, this.timeout);
    },
    debouncedModel: {
      get() { return this.value; },
      set(value) { this.updateValueDebounced(value); }
    },
  },
}
</script>

答案 8 :(得分:0)

如果您使用的是Vue,也可以使用v.model.lazy代替debounce,但请记住,v.model.lazy不会总是起作用,因为Vue限制了自定义组件。

对于自定义组件,您应该将:value@change.native一起使用

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

答案 9 :(得分:0)

我们可以通过使用几行JS代码来做到这一点:

if(typeof window.LIT !== 'undefined') {
      clearTimeout(window.LIT);
}

window.LIT = setTimeout(() => this.updateTable(), 1000);

简单的解决方案!做工完美!希望对您有所帮助。

答案 10 :(得分:0)

如果需要通过lodash的debounce函数应用动态延迟:

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) {
    // ...
  }
}

和模板:

<template>
  //...

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

  //...
</template>

注意::在上面的示例中,我举了一个搜索输入示例,该输入可以调用props

中提供的自定义延迟来调用API

答案 11 :(得分:0)

尽管这里几乎所有答案都是正确的,但是如果有人正在寻找快速解决方案,我对此有一个指示。 https://www.npmjs.com/package/vue-lazy-input

它适用于@input和v模型,支持自定义组件和DOM元素,反跳和限制。

Vue.use(VueLazyInput)
  new Vue({
    el: '#app', 
    data() {
      return {
        val: 42
      }
    },
    methods:{
      onLazyInput(e){
        console.log(e.target.value)
      }
    }
  })
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/lodash/lodash.min.js"></script><!-- dependency -->
<script src="https://unpkg.com/vue-lazy-input@latest"></script> 

<div id="app">
  <input type="range" v-model="val" @input="onLazyInput" v-lazy-input /> {{val}}
</div>

答案 12 :(得分:0)

如果您可以将反跳功能的执行转移到某些类方法中,则可以使用utils-decorators库(npm install --save utils-decorators)中的装饰器:

import {debounce} from 'utils-decorators';

class SomeService {

  @debounce(500)
  getData(params) {
  }
}

答案 13 :(得分:0)

1 使用箭头功能的简短版本,默认延迟

file: debounce.js in ex: ( import debounce from '../../utils/debounce' )

export default function (callback, delay=300) {
    let timeout = null
    return (...args) => {
        clearTimeout(timeout)
        const context = this
        timeout = setTimeout(() => callback.apply(context, args), delay)
    }
}

2 Mixin 选项

文件:debounceMixin.js

export default {
  methods: {
    debounce(func, delay=300) {
      let debounceTimer;
      return function() {
       // console.log("debouncing call..");
        const context = this;
        const args = arguments;
        clearTimeout(debounceTimer);
        debounceTimer = setTimeout(() => func.apply(context, args), delay);
        // console.log("..done");
      };
    }
  }
};

在 vueComponent 中使用:

<script>
  import debounceMixin from "../mixins/debounceMixin";
  export default {
   mixins: [debounceMixin],
        data() {
            return {
                isUserIdValid: false,
            };
        },
        mounted() {
        this.isUserIdValid = this.debounce(this.checkUserIdValid, 1000);
        },
    methods: {
        isUserIdValid(id){
        // logic
        }
  }
</script>

另一种选择,例如

Vue search input debounce

答案 14 :(得分:-1)

 public debChannel = debounce((key) => this.remoteMethodChannelName(key), 200)

vue-property-decorator