使用自定义Ref实现防抖
本文最后更新于836 天前,其中的信息可能已经过时,如有错误请评论留言

在开发中我们经常会用到防抖,这里先给不知道防抖的同志简单说明一下:

防抖(debounce):n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时。可以简单理解为游戏中的回城,点击回城后等待 n 秒后回城(执行事件),如果在等待过程中再次点击回城则会重新进入回城倒计时。

与此相似的还有一个概念叫做节流,这里也简单说明一下,便于大家区分理解和记忆

节流(throttle):n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效。可以简单理解为游戏中的技能释放,点击后技能即刻释放(执行事件),随即进入冷却无法释放技能,冷却结束后再次点击技能后才会释放。

了解了基础知识之后,我们来看下面这样一段代码,我们要在其上增加防抖

<template>
    <div class="container">
        <input v-model="text" />
        <p class="result">{{ text }}</p>
    </p>
    </div>
</template>
<script setup>
    import { ref } from 'vue'
    const text = ref('')
</script>
<style scoped>
</style>

经典实现

我们既然要实现防抖,正常情况下上面代码中的v-model就不能直接用了,我们可以先将其改写成原始状态,如下:

<template>
    <div class="container">
        <input :value="text" @input="handleUpdate" />
        <p class="result">{{ text }}</p>
    </p>
    </div>
</template>
<script setup>
    import { ref } from 'vue'
    const text = ref('')

    const handleUpdate = (e) => {
        text.value = e.target.value
    }
</script>

要实现防抖,即是要让数据的变化延迟执行,这样我们可以设置一个计时器,使其隔段时间再去改变数据

<template>
    <div class="container">
        <input :value="text" @input="handleUpdate" />
        <p class="result">{{ text }}</p>
    </p>
    </div>
</template>
<script setup>
    import { ref } from 'vue'
    const text = ref('')
    let timer
    const handleUpdate = (e) => {
        clearTimeout(timer)
        timer = setTimeout(() => {
            text.value = e.target.value
        }, 1000)
    }
</script>

上面基本实现了防抖,但是每次都要写那么多并不优雅,所以我们将其封装为一个防抖函数放在debounce.js文件中,并在原来的文件中使用它

// debounce.js
export function debounce(func, delay = 1000){
    let timer
    return function(...args){
        clearTimeout(timer)
        timer = setTimeout(() => {
            func.call(this, ...args)
        }, delay)
    }
}
<template>
    <div class="container">
        <input :value="text" @input="handleUpdate" />
        <p class="result">{{ text }}</p>
    </p>
    </div>
</template>
<script setup>
    import { ref } from 'vue'
    import { debounce } from './debounce'
    const text = ref('')
    const update = (e) => (text.value = e.target.value)
    const handleUpdate = debounce(update, 1000)
</script>

这样我们就较为优雅地实现了防抖,不过有没有一种方法可以使我们使用最初的v-model的情况下也能实现防抖呢?下面我们进入本文的正题,使用自定义Ref实现防抖

自定义Ref实现防抖

在这之前,我们先来简单了解一下,Vue中的ref()在源码中大概是怎样的形式,直接看代码比文字描述更清晰,我们来简单描述一下ref()的部分大框

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

因为Vue是响应式的,所以需要track()和trigger()进行依赖收集和派发更新形成响应式,有点像发布订阅模式。在了解了以后,我们就可以着手写一个自己的ref()函数了,尤大提前考虑到了这点,为我们提供了customRef方便我们根据需要自定义ref。下面我们就利用customRef来实现防抖,为方便复用我们将代码封装在debounceRef.js中,并在最初的文件中调用

// debounceRef.js
import { customRef } from 'vue'
export function debounceRef(value){
    return customRef((track, trigger) => {
        return {
            get(){
                track() // 依赖收集
                return value
            },
            set(val) {
                value = val;
                trigger(); // 派发更新
            }
        }
    })
}
<template>
    <div class="container">
        <input v-model="text" />
        <p class="result">{{ text }}</p>
    </p>
    </div>
</template>
<script setup>
    import { debounceRef } from './debounceRef'
    const text = debounceRef('')
</script>

可以测试一下效果,与使用Vue自身的ref()函数实现的效果是相同的。到此就很简单了,我们只需要如法炮制,使用定时器控制派发更新即可达到防抖的效果,如下:

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

这样,我们就完美地实现了防抖,在使用中甚至感觉不到有什么变化,一个字——雅!

真是 枯藤老树昏鸦,代码高级优雅~ ヾ(≧▽≦*)o

山水有相逢,我们江湖再见!じゃな~
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇