第三十七节:防抖、节流封装(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