search

Home  >  Q&A  >  body text

Anti-shake implementation method in Vue3

<p>I have a filter input box and want to filter a list of items. The list is large, so I want to use antishake to delay applying the filter until the user stops typing to improve user experience. This is my input box which is bound to filterText for filtering the list. </p> <pre class="brush:php;toolbar:false;"><input type="text" v-model="state.filterText" /></pre>
P粉055726146P粉055726146488 days ago653

reply all(2)I'll reply

  • P粉879517403

    P粉8795174032023-08-25 11:20:55

    Hi, first time answering a question here, so please feel free to correct my answer, I'll be very grateful. I think the most beautiful and lightweight solution is to create a directive globally that you can use randomly in all your forms.

    First create a file with directives, eg. debouncer.js

    Then create the anti-shake function

        //debouncer.js
        /*
          这是一个典型的防抖函数,它接收“callback”和等待发出事件的时间
        */
        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)
            }
          }
    
        /*
          此函数接收指令将设置在其中的元素和设置在其中的值
          如果值已更改,则重新绑定事件
          它具有默认超时时间为500毫秒
        */
        module.exports = function debounce(el, binding) {
          if(binding.value !== binding.oldValue) {
            el.oninput = debouncer(function(){
              el.dispatchEvent(new Event('change'))
            }, parseInt(binding.value) || 500)
          }
        }
    

    After defining this file, you can go to your main.js to import it and use the exported functions.

        //main.js
        import { createApp } from 'vue'
        import debounce from './directives/debounce' // 导入的文件
        
        const app = createApp(App)
    
        //定义指令
        app.directive('debounce', (el,binding) => debounce(el,binding))
    
        app.mount('#app')
    

    Done, when you want to use a directive in an input box, just do it like this, no need to import or anything else.

        //Component.vue
        <input
           :placeholder="按名称筛选"
           v-model.lazy="filter.value" v-debounce="400"
        />
    

    The v-model.lazy directive is very important if you choose to do it this way, because by default it will update bound properties on input events, but setting this directive will make it wait for change events, And this is the event that we emit in the antishake function. Doing so will stop v-model from automatically updating until you stop input or the timeout expires (can be set in the directive's value). Hope that makes it clear.

    reply
    0
  • P粉550257856

    P粉5502578562023-08-25 10:05:26

    I didn't find a satisfactory solution because I wanted to see my bindings in the template, so I decided to share my solution. I wrote a simple debounce function and bound the behavior using the following syntax:

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

    The template syntax is as follows:

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

    reply
    0
  • Cancelreply