Vue anti-shake custom ref realizes input box anti-shake

       Anti-shake (debounce): When the event is continuously triggered, the event processing function will only be executed once if the event is not triggered again within a certain period of time. If the event is triggered again before the set time arrives, the timing will be restarted.

      Next, I will take you step by step to analyze how to achieve the ultimate input anti-shake,

      First, you need to disassemble the two-way binding v-mode of input into a value and an input event, register a function debUpdata in the event, get the input input content in debUpdata and assign it to text, which is similar to handwriting v-mode, the code is as follows:

<template>
  <div class="hello">
    <input :value="text" @input="debUpdata" />
    <p>{
   
   { text }}</p>
  </div>
</template>

<script>
<script setup>
  import{ref} from 'vue';
  const text =ref('');
  const debUpdata=(e)=> {
  this.text = e.target.value;
}
</script>

       The specific anti-shake operation can be performed in the debUpdata function. The so-called anti-shake is nothing more than delaying the execution of data changes, so define a timer in debUpdata, clear the timer every time the function is executed, and then change the value of text after using setTimeout for one second to achieve the most basic anti-shake. code show as below:

 debUpdata(e) {
      clearTimeout(this.timer);
      this.timer = setTimeout(() => {
        this.text = e.target.value;
      }, 1000);
    }

       If you need to write this function every time for input anti-shake, it will be somewhat troublesome, then how to optimize it and separate it into a separate anti-shake function?

Create a new debounce.js file to encapsulate a function debounce 

export function debounce(func, delay = 1000) {
    let timer;
    return function (...args) {
        clearTimeout(timer);
        timer = setTimeout(() => {
            func.call(this, ...args);
        }, delay);
    }
}

After encapsulation, call it every time it is used:

<template>
  <div class="app">
    <input :value="text" @input="debUpdata" />
    <p>{
   
   { text }}</p>
  </div>
</template>

<script setup>
import { debounce } from "./debounce";
import{ref} from 'vue';
const text=ref('');
const update=(e)=>(text.value=e.target.value);
const debUpdata=debounce(update,1000);
</script>

       Although the effect is realized, it needs to be referenced every time it is used, and then use debUpdata to call a real update function. If all input boxes need to be anti-shake, it will be a bit troublesome. Next, let's continue to optimize the above code! !

What is the ref of vue?

797e6973628c4211aadead9671b00dc9.jpeg

         It is printed out as a RefImpl object, and there is a value in the object, which is defined by Object.defineProperty. After the definition of Object.defineProperty, a get and set function will be generated. For details, please refer to the official document of Object.defineProperty. That is to say, the source code of the ref method provided by vue contains get and set. In addition, vue is responsive. It is to notify the previously used place to update the response   . So you might as well make a bold guess that the structure of the ref function should be similar:

function ref(value) {
    {
        get(){
            // 依赖收集 track()
            return value;
        },
        set(val){
            //派发更新 trigger()
            value = val;
        }
    }
}

       If you want to implement delayed data updates, you can directly delay data updates, which is equivalent to delaying set distribution updates in ref. Does it need to manually rewrite the vue source code to achieve anti-shake? Of course not, vue provides us with a custom ref entry called customRef  , which can customize the get and set methods

4e2f92f88a474c7b86c1b3955c3bd852.png

Use customRef to declare function debounceRef to customize get and set

import {customRef} from 'vue'
export function debounceRef(value,delay=1000){
    // return ref(value) //原始get set
    return customRef(()=>{
        return {
            get(){
                // 依赖收集 track()
                return value;
            },
            set(val){
                //派发更新 trigger()
                value = val;
            }
        }
    })
}

      First of all, in addition to returning a value, get also needs to collect dependencies. Regarding dependency collection, Vue has taken this into consideration. He passed in a parameter called track, which is a method. As long as this method is called, it will automatically collect dependencies. Colleagues also passed in a parameter called trigger. As long as the trigger method is called, the dispatch update will be triggered;

 ref vs custom ref

9a935a7fa99b43b6a8a7fa4dbdd19bd9.jpeg

all codes

import { customRef } from 'vue'
export function debounceRef(value, delay = 1000) {
    let timer;
    // return ref(value) //原始get set
    return customRef((track, trigger) => {
        return {
            get() {
                // 依赖收集 track()
                track();
                return value;
            },
            set(val) {
                clearTimeout(timer)
                timer = setTimeout(() => {
                    //派发更新 trigger()
                    value = val;
                    trigger()
                }, delay);
            }
        }
    })
}

Instructions

<template>
  <div class="app">
    <input v-model="text" />
    <p>{
   
   { text }}</p>
  </div>
</template>

<script setup>
import { debounceRef } from "./ref";
const text=debounceRef('');
</script>

Feel the comparison before and after! !

5ab95c3d81ab4ae499ef9bc2576473d5.png

 Welcome everyone to leave a message to communicate

Guess you like

Origin blog.csdn.net/2303_76218115/article/details/129113550