前言 📝
在前端开发中,防抖(debounce)是一种常见的技术,用于限制函数执行的频率。特别是在处理用户输入、窗口大小调整等频繁触发的事件时,防抖可以显著提高性能。本文将探讨在Vue3中实现防抖的几种方法,并分析它们的优缺点。
1. 什么是防抖?
防抖是一种技术,它确保一个函数在一定时间内只执行一次,即使它被多次调用。如果在等待时间内再次调用该函数,计时器会重置。
典型应用场景:
2. Vue中的防抖实现方案
2.1 使用工具函数实现防抖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| export default function debounce<T extends (...args: any[]) => any>( fn: T, delay = 300 ): (...args: Parameters<T>) => void { let timer: ReturnType<typeof setTimeout> | null = null; return function(...args: Parameters<T>) { if (timer) { clearTimeout(timer); } timer = setTimeout(() => { fn(...args); }, delay); }; }
|
使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <script setup lang="ts"> import { ref } from "vue"; import debounce from './debounce.ts'
const message = ref('');
const handleChange = (e) => { console.log('执行') message.vlaue = e.target.value } const debounceFn = debounce(handleChange, 3000) </script>
<template> <input @input="debounceFn" /> <p style="color: #fff">{{message}}</p> </template>
|
优点:
- 通用性强,可以在任何地方使用
- 不依赖Vue特性,纯JavaScript实现
缺点:
2.2 响应式Ref防抖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import { customRef, onUnmounted } from "vue";
export default function useDebounceRef<T>(value: T, delay = 200) { let timer: ReturnType<typeof setTimeout> | null = null;
onUnmounted(() => { if (timer) clearTimeout(timer) }) return customRef((track, trigger) => ({ get() { track(); return value; }, set(newValue: T) { if (timer) { clearTimeout(timer); } timer = setTimeout(() => { value = newValue; trigger(); }, delay); }, })); }
|
使用:
1 2 3 4 5 6 7 8 9 10 11
| <script setup lang="ts"> import { ref } from "vue"; import useDebounceRef from './useDebounceRef.ts'
const message = useDebounceRef('', 3000); </script>
<template> <input v-model="message" /> <p style="color: #fff">{{message}}</p> </template>
|
优点:
- 无缝支持 v-model:可以直接在模板中使用
v-model
绑定,开发者体验极佳
- 自动依赖追踪:通过
track()
和 trigger()
方法完美融入 Vue 的响应式系统
- 类型安全:完整的 TypeScript 支持,保留了类型推断
- 简洁直观的 API 设计
缺点:
customRef
谨慎使用
当使用 customRef 时,我们应该谨慎对待其 getter 的返回值,尤其是在每次运行 getter 时都生成新对象数据类型的情况下。当这样的 customRef 作为 prop 传递时,将影响父组件和子组件之间的关系。
父组件的渲染函数可能会被其他的响应式状态变化触发。在重新渲染过程中,我们会重新评估 customRef 的值,并返回一个新的对象数据类型作为子组件的 prop。这个 prop 会与其上一个值进行比较,由于两者不同,子组件中 customRef 的响应式依赖将被触发。与此同时,因为没有调用 customRef 的 setter,父组件中的响应式依赖不会运行。
在演练场中尝试一下