第三十七节:防抖、节流封装(composables 通用函数,搜索框防重复请求)

第三十七节:防抖、节流封装(composables 通用函数,搜索框防重复请求)

🎯本节目标

  1. 区分防抖 debounce 、节流 throttle
    • 防抖:输入框搜索,停止输入后延迟执行(适合搜索输入)
    • 节流:滚动、窗口缩放,固定间隔执行(适合滚动、按钮频繁点击)
  2. 封装成 composables 组合式函数,项目全局复用
  3. 用户管理页面搜索框接入防抖,防止连续输入疯狂发请求

原理简述

  • 防抖:每次触发就重置计时器,最后一次操作后等待 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>

✅ 测试清单

  1. 保存重启项目 pnpm dev,进入用户管理
  2. 在用户名输入框快速连续打字
    ✅ 不会每次打字立刻发接口,停止输入半秒后才请求一次
  3. 快速重复点击提交按钮(节流案例),1 秒内只执行一次

常见坑

  1. composables 函数只能在 setup 顶层调用,不能写在 if / 循环里面
  2. 组件销毁一定要清除定时器,避免内存泄漏
  3. delay 单位是毫秒,搜索一般 300~500,按钮节流推荐 1000
相关推荐
paopaokaka_luck1 分钟前
心理咨询管理系统(WebSocket实时沟通、基于用户的协同过滤、 ECharts多维分析、 预约业务流程、预约校验与定时处理)
java·vue.js·spring boot·mysql·spring·echarts·1024程序员节
特立独行的猫A7 分钟前
10 MB 的桌面 AI 客户端:用仓颉 + 系统 WebView 替代 Electron
前端·harmonyos
修炼的dance1 小时前
白底图存JPG,sharp开mozjpeg背景杂点少近三成
前端
anOnion1 小时前
构建无障碍组件之Grid Pattern
前端·html·交互设计
乔旭伟2 小时前
Vben3 中后台表格封装实战:useVbenVxeGrid 的全局收敛与七个坑
前端·anti-design-vue·1024程序员节
鶴哥只手遮天2 小时前
jQuery 4.0 源码架构与工程实践-第 10 章 尺寸、几何与显隐
前端·javascript·jquery
Mia_墨黎2 小时前
2026 Windows 11 终端美化完全指南
前端·后端
用户1880687493522 小时前
戴着 Rokid 接成语:用 AIUI 做一局有提示、有复盘的“接着说”
前端
Sakura_j_h_2 小时前
Three.js 单文件离线机械臂工作台:爆炸图、透明外壳与剖面
前端·机械臂·webgl·three.js·1024程序员节·esbuild
计算机魔术师4 小时前
管谷歌的不是Pichai一个人,是一整层AI智能体
前端