如何在vue3中实现去抖

g2ieeal7  于 2022-12-23  发布在  Vue.js
关注(0)|答案(6)|浏览(227)

我有一个筛选器输入字段,并希望筛选项目列表。该列表很大,因此我希望使用去抖动功能来延迟正在应用的筛选器,直到用户停止键入以改善用户体验。这是我的输入字段,它绑定到用于筛选列表的filterText。

<input type="text" v-model="state.filterText" />
jxct1oxe

jxct1oxe1#

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

setup() {
...

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

  return {
    state,
    debounce: createDebounce(),
  };
},

模板语法:

<input
      type="text"
      :value="state.filterText"
      @input="debounce(() => { state.filterText = $event.target.value })"
    />
w3nuxt5m

w3nuxt5m2#

你好,第一次在这里回答问题,所以请尽可能多地纠正我的答案,我会很感激。我认为最漂亮和最轻松的解决方案是创建一个全局指令,您可以在所有表单中使用它。
你首先用你的指令创建文件,例如 debouncer.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)
      }
    }

定义此文件后,您可以转到 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')

它完成了,当你想在一个输入上使用这个指令时,你只需要像这样做,没有导入或任何东西。

//Component.vue
    <input
       :placeholder="filter by name"
       v-model.lazy="filter.value" v-debounce="400"
    />

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

axr492tv

axr492tv3#

<template>
    <input type="text" :value="name" @input="test" />
    <span>{{ name }}</span>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
function debounce<T> (fn: T, wait: number) {
  let timer: ReturnType<typeof setTimeout>
  return (event: Event) => {
    if (timer) clearTimeout(timer)
    timer = setTimeout(() => {
      if (typeof fn === 'function') {
        fn(event)
      }
    }, wait)
  }
}

export default defineComponent({
  setup () {
    const name = ref('test')
    function setInputValue (event: Event) {
      const target = event.target as HTMLInputElement
      name.value = target.value
    }
    const test = debounce(setInputValue, 1000)
    return { name, test }
  }
})
</script>
utugiqy6

utugiqy64#

使用Lodash,您可以获得更简单的解决方案:

<template>
    <input type="text" :value="name" @input="onInput" />
    <span>{{ name }}</span>
</template>

<script>
import debounce from "lodash/debounce"
export default {
  setup () {
    const onInput = debounce(() => {
      console.log('debug')
    }, 500)
    return { onInput }
  }
}
</script>
sbdsn5lh

sbdsn5lh5#

你可以试试这个

4xrmg8kj

4xrmg8kj6#

以下是Lodash和脚本设置语法的示例,使用观察器触发去抖API调用:

<script setup>
import { ref, watch } from 'vue'
import debounce from 'lodash.debounce'

const searchTerms = ref('')

const getFilteredResults = async () => {
  try {
    console.log('filter changed')
    // make axios call here using searchTerms.value
  } catch (err) {
    throw new Error(`Problem filtering results: ${err}.`)
  }
}

const debouncedFilter = debounce(getFilteredResults, 250) // 250ms delay

watch(() => searchTerms.value, debouncedFilter)    
</script>

<template>
    <input v-model="searchTerms" />
</template>

相关问题