Anti-shake implementation method in Vue3
P粉055726146
P粉055726146 2023-08-24 12:07:02
0
2
654
<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粉055726146
P粉055726146

reply all(2)
P粉879517403

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.

P粉550257856

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 })"
    />
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template