Vuejs 2: 在watch选项上防抖不起作用

4
当我在VueJs中对这个函数进行去抖处理时,如果我提供一个原始的毫秒数,它能够正常工作。但是,如果我将其作为一个prop的引用提供,它会被忽略。
以下是props的简化版本:
props : {
    debounce : {
        type : Number,
        default : 500
    }
}

以下是不起作用的手表选项:

watch : {
    term : _.debounce(function () {
        console.log('Debounced term: ' + this.term);
    }, this.debounce)
}

这里有一个可行的观察选项:

watch : {
    term : _.debounce(function () {
        console.log('Debounced term: ' + this.term);
    }, 500)
}

我怀疑这是一个作用域问题,但我不知道如何解决。如果我将watch方法替换为以下内容...

watch : {
    term : function () {
        console.log(this.debounce);
    }
}

我在控制台中看到正确的去抖值(500)。


2
这是一个作用域问题。您可以在像“created”这样的生命周期钩子中定义this.$watch,然后您将收到this.debounce的正确值。https://vuejs.org/v2/api/#vm-watch - Eric Guan
4个回答

6
另一种方法是在created()中构建观察器函数,这是对@Bert答案的另一种变化。

// SO: Vuejs 2: debounce not working on a watch option

console.clear()

Vue.component("debounce",{
  props : {
    debounce : {
      type : Number,
      default : 500
    }
  },
  template:`
    <div>
      <input type="text" v-model="term">
    </div>
  `,
  data(){
    return {
      term: "",
      debounceFn: null
    }
  },
  created() {
    this.debounceFn = _.debounce( () => {
      console.log('Debounced term: ' + this.term);
    }, this.debounce)
  },
  watch : {
    term : function () {
      this.debounceFn();
    }
  },
})

new Vue({
  el: "#app"
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<div id="app">
  <debounce :debounce="2000"></debounce>
</div>

CodePen示例上的实例


2
这里的主要问题是在定义防抖函数时使用了this.debounce作为间隔。当运行_.debounce(...)(组件正在编译时)时,该函数尚未附加到Vue上,因此this不是Vue,this.debounce将未定义。因此,在创建组件实例后,您需要定义观察器。Vue允许您使用$watch来实现这一点。
我建议您将其添加到created生命周期处理程序中。
created(){
  this.unwatch = this.$watch('term', _.debounce((newVal) => {
     console.log('Debounced term: ' + this.term);
  }, this.debounce))
},
beforeDestroy(){
  this.unwatch()
}

请注意,上述代码还调用了 unwatch 方法,在组件销毁前进行清理。通常情况下,Vue 会自动处理这个问题,但由于这里是手动添加 watch,所以也需要手动管理 watch 的清除。当然,您需要将 unwatch 添加为数据属性。
下面是一个可用的示例。

console.clear()

Vue.component("debounce",{
  props : {
    debounce : {
      type : Number,
      default : 500
    }
  },
  template:`
    <input type="text" v-model="term">
  `,
  data(){
    return {
      unwatch: null,
      term: ""
    }
  },
  created(){
    this.unwatch = this.$watch('term', _.debounce((newVal) => {
      console.log('Debounced term: ' + this.term);
    }, this.debounce))
  },
  beforeDestroy(){
    this.unwatch()
  }
})

new Vue({
  el: "#app"
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<script src="https://unpkg.com/vue@2.4.2"></script>
<div id="app">
  <debounce :debounce="250"></debounce>
</div>


2
“debounced method”需要被抽象出来,因为每次触发“watch”时我们需要调用同一个函数。如果我们把“debounced”方法放在Vue的计算属性或者观察属性中,它将会在每次被更新时被重新创建。”

const debouncedGetData = _.debounce(getData, 1000);

function getData(val){
  this.newFoo = val;
}

new Vue({
  el: "#app",
  template: `
    <div>
      <input v-model="foo" placeholder="Type something..." />
      <pre>{{ newFoo }}</pre>
    </div>
`,
    data(){
      return {
        foo: '',
        newFoo: ''
      }
    },
    watch:{
      foo(val, prevVal){
        debouncedGetData.call(this, val);
      }
    }
  
  })
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="app"></div>

祝你好运...


0

new Vue({
  el: '#term',
  data: function() {
    return {
      term: 'Term',
      debounce: 1000
    }
  },
  watch: {
    term : _.debounce(function () {
        console.log('Debounced term: ' + this.term);
    }, this.debounce)
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.js"></script>
<div id="term">
  <input v-model="term">
</div>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接