如何在Vue.js中使用防抖技术处理`keyup`事件

3

我正在尝试使用debounce函数捕获用户开始输入和停止输入的事件。我尝试了LodashUnderscore.js

On my textArea
                               v-on:keyup="handler($event)"

handler: function(e) {
             this.e = e
             if(this.canPublish) {
                 this.setCanNotPublish()
                 this.doStuff()
             }

             var debounceFunction = _.debounce(this.doneTyping(), 5000)
             debounceFunction(e)

         },

我对此感到非常沮丧。在纯JavaScript中,我使测试工作了。但是在使用v-on事件、数据、方法等的Vue.js中,我无法使其工作。

方法doneTyping

doneTyping: function () {
                console.log('done typing....')
            }

}

Method doStuff

doStuff: function () {
             console.log('started typing....')
         }

预期的行为是:用户首先在文本区域中开始输入,然后启动doStuff。如果用户继续输入时间小于5秒的句号,则不会再次触发doStuff,因为canPublish是一个布尔值。接下来,用户停止输入,然后防抖函数完成,doneTyping被触发。


你能展示一下你的 this.doneTyping 代码吗?this.doneTyping 应该返回一个函数,因为在 _.debounce 中的第一个参数是函数。 - undefined
@TingsenCheng,添加了doneTyping,它是基本的console.log。 - undefined
2个回答

4
我会使用两个防抖函数,一个用于开始输入并在前沿触发,另一个用于停止输入并在后沿触发。

new Vue({
  el: '#app',
  
  created() {
    this.startedTyping = _.debounce(this.startedTyping, 5000, {
      leading: true,
      trailing: false,
    })
    this.stoppedTyping = _.debounce(this.stoppedTyping, 5000, {
      leading: false,
      trailing: true,
    })
  },
  
  methods: {
    handleKeydown() {
      // This triggers on the leading edge
      this.startedTyping()

      // This triggers on the trailing edge (after 5s)
      this.stoppedTyping()
    },
    
    startedTyping() {
      console.log('started typing')
    },
    
    stoppedTyping() {
      console.log('stopped typing')
    },
  },
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.19/lodash.min.js"></script>

<div id="app">
  <textarea @keydown="handleKeydown"></textarea>
</div>

你的代码有误,因为你每次调用处理程序时都会创建一个新的防抖函数。你需要仅拥有一个防抖函数实例来进行每次调用。最好在created钩子中创建防抖函数。
我经常看到这样的代码:
methods: {
  myDebouncedFunc: _.debounce(function () {
    // Do stuff
  }, 1000)
}

从技术上讲,这并没有错,但您可能不知道防抖函数将在该组件的所有实例之间共享,这可能不是您想要的。通常最好在created钩子中创建防抖函数,以便组件的每个实例都有自己独立的防抖跟踪。


快速问题,为什么你在你的回答中使用keydown而不是keyup - undefined
没有特别的原因,我可能应该使用keyup来与你的保持一致。也可以使用input - undefined
这个问题是如果开始输入然后停止,是否会出现错误?而不是将其绑定到控制台,我将其绑定到一个模型并在屏幕上显示,但是当我在停止方法中清除它时,它从未消失。而且该模型来自于Vuex,如果有任何区别的话。 - undefined
听起来像是一个不同的问题,但应该可以解决。你可以尝试将日志记录到控制台的方式改为设置/清除一个布尔标志,并将其绑定到模板中的某个元素上。如果还是不起作用,那可能是其他问题导致的,我无法得知具体情况。或许你可以提出另一个问题来寻求帮助? - undefined
你说得对,似乎是不同的问题。在这里发布了。 https://stackoverflow.com/questions/62968511/vuejs-infinite-update-loop-in-a-component-render-function - undefined

1

以下是如何防抖你的方法。

doneTyping: _.debounce(function (e) {
    console.log('done typing....')
}, 5000)

然后您可以像这样使用它。
handler: function(e) {
    this.e = e
    if(this.canPublish){
        this.setCanNotPublish()
        this.doStuff()
    }

    this.doneTyping() // function is debounced
},

因为我需要调用this.setCanNotPublish(),所以无法做到这一点,因为我正在尝试检测用户开始输入和停止输入。 - undefined
好的,你可能想要使用_.debounce(this.doneTyping, 5000)_.debounce接受一个函数引用作为参数。this.doneTyping是一个函数的引用,而this.doneTyping()不是,除非它返回一个函数,但我怀疑它不会这样做。 - undefined
我修改了问题,并解释了我真正的目标。 - undefined
请注意,这会为所有组件实例保持相同的去抖延迟,这很少是理想的。更好的方式是按照被接受的答案所示进行操作。 - undefined

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