vue3中如何实现debounce

And*_*dre 7 debouncing vue.js vuejs3

我有一个过滤器输入字段,想要过滤项目列表。该列表很大,因此我想使用去抖动来延迟应用过滤器,直到用户停止键入以改善用户体验。这是我的输入字段,它绑定到用于过滤列表的filterText。

<input type="text" v-model="state.filterText" />
Run Code Online (Sandbox Code Playgroud)

And*_*dre 16

我没有找到任何好的解决方案,因为我想在模板中看到我的绑定,所以我决定分享我的解决方案。我编写了一个简单的去抖动函数,并使用以下语法来绑定行为:

setup() {
...

  function createDebounce() {
    let timeout = null;
    return function (fnc, delayMs) {
      clearTimeout(timeout);
      timeout = setTimeout(() => {
        fnc();
      }, delayMs || 500);
    };
  }

  return {
    state,
    debounce: createDebounce(),
  };
},
Run Code Online (Sandbox Code Playgroud)

以及模板语法:

    <input
      type="text"
      :value="state.filterText"
      @input="debounce(() => { state.filterText = $event.target.value })"
    />
Run Code Online (Sandbox Code Playgroud)


小智 13

您好,第一次在这里回答问题,所以请尽可能纠正我的答案,我将不胜感激。我认为最漂亮、最轻量的解决方案是在全局范围内创建一个指令,您可以在所有表​​单中随意使用它。

您首先使用您的指令创建文件,例如。 防抖器.js

然后您创建去抖函数

    //debouncer.js
    /*
      This is the typical debouncer function that receives
      the "callback" and the time it will wait to emit the event
    */
    function debouncer (fn, delay) {
        var timeoutID = null
        return function () {
          clearTimeout(timeoutID)
          var args = arguments
          var that = this
          timeoutID = setTimeout(function () {
            fn.apply(that, args)
          }, delay)
        }
      }

    /*
      this function receives the element where the directive
      will be set in and also the value set in it
      if the value has changed then it will rebind the event
      it has a default timeout of 500 milliseconds
    */
    module.exports = function debounce(el, binding) {
      if(binding.value !== binding.oldValue) {
        el.oninput = debouncer(function(){
          el.dispatchEvent(new Event('change'))
        }, parseInt(binding.value) || 500)
      }
    }
Run Code Online (Sandbox Code Playgroud)

定义此文件后,您可以转到main.js导入它并使用导出的函数。

    //main.js
    import { createApp } from 'vue'
    import debounce from './directives/debounce' // file being imported
    
    const app = createApp(App)

    //defining the directive
    app.directive('debounce', (el,binding) => debounce(el,binding))

    app.mount('#app')
Run Code Online (Sandbox Code Playgroud)

就完成了,当你想在输入上使用指令时,你只需这样做,不需要导入或任何东西。

    //Component.vue
    <input
       :placeholder="filter by name"
       v-model.lazy="filter.value" v-debounce="400"
    />
Run Code Online (Sandbox Code Playgroud)

如果您选择这样做,则 v-model.lazy 指令很重要,因为默认情况下它将更新输入事件上的绑定属性,但设置此指令将使其等待更改事件,这是我们的事件在我们的去抖动函数中发出。这样做将停止 v-model 更新自身,直到您停止写入或超时(您可以在指令的值中设置)。我希望这是可以理解的。

  • 不错的方法。我尝试使用它,但有一个问题 - 当我从 vue 组件发出 `update:model-value` 时,`$event` 只是新值,而不是像原生 html 组件那样的 js 事件对象。因此,当我听“@change”时,我收到 js 事件,但无法访问新值。知道如何解决这个问题吗?我尝试添加 `debouncer(function(inputEvent){....})`,但它似乎不是从组件发出的事件。我认为 `el.oninput` 需要替换为 `@update:model-value` 的等价项,而不是 dom 的事件监听器,但我不知道该怎么做 (2认同)

Kit*_*Kit 11

对于一些更简单的解决方案,您可以使用流行的库:

  1. 使用洛达什
<template>
  <input type="text" v-model="searchText" @input="onInput" />
</template>

<script setup>
import debounce from "lodash/debounce"
const onInput = debounce(() => {
  console.log(searchText.value)
}, 500)
</script>
Run Code Online (Sandbox Code Playgroud)
  1. 使用vue使用:
<template>
  <input type="text" v-model="searchText" @input="onInput" />
</template>

<script setup>
import { useDebounceFn } from "@vueuse/core"
const onInput = useDebounceFn(() => {
  console.log(searchText.value)
}, 500)
</script>
Run Code Online (Sandbox Code Playgroud)