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

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

然而,在Vue 2中debounce属性已被弃用。建议只说:“使用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)
}

然后在计算道具中使用过滤键。


当前回答

我可以用很少的实现来使用debounce。

我使用Vue 2.6.14与boostrap-vue:

把这个pkg加到你的包裹里。json: https://www.npmjs.com/package/debounce

将此添加到main.js:

import { debounce } from "debounce";
Vue.use(debounce);

在我的组件中,有这样的输入:

          <b-form-input
            debounce="600"
            @update="search()"
            trim
            id="username"
            v-model="form.userName"
            type="text"
            placeholder="Enter username"
            required
          >
          </b-form-input>

它所做的就是调用search()方法,而搜索方法使用表单。执行搜索的用户名。

其他回答

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

它适用于@input和v-model,支持自定义组件和DOM元素,debounce和throttle。

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>

我也有同样的问题,这里有一个解决方案,没有插件。

因为<input v-model="xxxx">与

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

(源)

我想我可以在xxxx = $event.target.value中为xxxx赋值时设置一个debounce函数

像这样

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

要创建debpublished方法,你可以使用computed,这样它们就不会在组件的多个实例之间共享:

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

如果你需要一个非常简约的方法,我做了一个(最初从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>

在方法中分配debounce可能会很麻烦。所以不要这样:

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

你可以试试:

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

如果您有一个组件的多个实例,这就会成为一个问题——类似于数据应该是一个返回对象的函数。每个实例都需要自己的debounce函数,如果它们被认为是独立的。

这里有一个问题的例子:

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