第三十七节:防抖、节流封装(composables 通用函数,搜索框防重复请求)
🎯本节目标
- 区分防抖 debounce 、节流 throttle
- 防抖:输入框搜索,停止输入后延迟执行(适合搜索输入)
- 节流:滚动、窗口缩放,固定间隔执行(适合滚动、按钮频繁点击)
- 封装成
composables组合式函数,项目全局复用 - 用户管理页面搜索框接入防抖,防止连续输入疯狂发请求
原理简述
- 防抖:每次触发就重置计时器,最后一次操作后等待 delay 才执行
- 节流:规定时间内,最多只执行一次
步骤 1:新建文件 src/composables/useDebounceThrottle.js
import { ref } from 'vue'
// 防抖
export function useDebounce(fn, delay = 500) {
const timer = ref(null)
const debounceFn = (...args) => {
// 每次触发清除旧定时器
if (timer.value) clearTimeout(timer.value)
timer.value = setTimeout(() => {
fn(...args)
}, delay)
}
// 手动取消防抖
const cancel = () => {
if (timer.value) {
clearTimeout(timer.value)
timer.value = null
}
}
return { debounceFn, cancel }
}
// 节流
export function useThrottle(fn, delay = 500) {
const lastTime = ref(0)
const throttleFn = (...args) => {
const now = Date.now()
if (now - lastTime.value >= delay) {
lastTime.value = now
fn(...args)
}
}
return { throttleFn }
}
步骤 2:用户列表页面接入防抖(src/views/system/user/user.vue)
原来的搜索是输入框 change 或者点击查询,现在输入框实时搜索用防抖
<template>
<PageCard title="用户管理">
<el-form :model="queryParams" inline>
<el-form-item label="用户名">
<!-- 绑定防抖后的查询方法 -->
<el-input
v-model="queryParams.username"
placeholder="请输入用户名"
clearable
@input="handleSearch"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="getList">查询</el-button>
<el-button @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 表格省略 -->
</PageCard>
</template>
<script setup>
import { ref, reactive, onUnmounted } from 'vue'
// 引入防抖
import { useDebounce } from '@/composables/useDebounceThrottle'
import { getUserListApi } from '@/api/system/user'
defineOptions({
name: 'UserList'
})
const queryParams = reactive({
username: '',
pageNum: 1,
pageSize: 10
})
const tableData = ref([])
const total = ref(0)
// 获取列表
const getList = async () => {
const res = await getUserListApi(queryParams)
if(res.code ===200){
tableData.value = res.data.records
total.value = res.data.total
}
}
// ✅ 包装防抖,500毫秒延迟
const { debounceFn: handleSearch, cancel } = useDebounce(getList, 500)
// 组件销毁,清除定时器,防止内存泄漏
onUnmounted(()=>{
cancel()
})
// 重置
const resetQuery = () => {
queryParams.username = ''
queryParams.pageNum = 1
getList()
}
getList()
</script>
步骤 3:按钮频繁点击场景(节流示例,防止重复提交)
import { useThrottle } from '@/composables/useDebounceThrottle'
// 提交按钮,1s内只能点击一次
const submitForm = async () => {
console.log('提交表单')
}
const { throttleFn: handleSubmit } = useThrottle(submitForm,1000)
模板:
<el-button type="primary" @click="handleSubmit">提交</el-button>
✅ 测试清单
- 保存重启项目
pnpm dev,进入用户管理 - 在用户名输入框快速连续打字
✅ 不会每次打字立刻发接口,停止输入半秒后才请求一次 - 快速重复点击提交按钮(节流案例),1 秒内只执行一次
常见坑
- composables 函数只能在 setup 顶层调用,不能写在 if / 循环里面
- 组件销毁一定要清除定时器,避免内存泄漏
- delay 单位是毫秒,搜索一般 300~500,按钮节流推荐 1000