【问题标题】:How to implement debounce in vue3如何在 vue3 中实现 debounce
【发布时间】:2021-03-07 11:22:47
【问题描述】:

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

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

【问题讨论】:

    标签: vue.js vuejs3 debounce


    【解决方案1】:

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

    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 })"
    />
    

    【讨论】:

    • 我会从setup 返回去抖动的方法,所以模板只做@input="debouncedFilter"。在设置中,返回debouncedFilter: createDebounce((evt)=&gt;{state.filterText=evt.target.value})
    【解决方案2】:
    <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>
    

    【讨论】:

      【解决方案3】:

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

      您首先使用您的指令创建文件,例如。 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-model 更新自身,直到您停止写入或超时用完(您可以在指令的值中设置)。 我希望这是可以理解的。

      【讨论】:

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

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

      【讨论】:

        猜你喜欢
        • 2021-12-29
        • 2020-12-19
        • 2021-10-29
        • 2020-07-18
        • 2023-02-24
        • 2023-03-19
        • 2022-12-04
        • 1970-01-01
        • 2014-02-21
        相关资源
        最近更新 更多