第三十七节:防抖、节流封装(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
相关推荐
恋猫de小郭8 分钟前
Android CLI 支持 AI Agent 通过 Device Streaming 调试云真机
android·前端·flutter
Wang's Blog10 分钟前
Java 项目实战: 外卖平台优化-前端dist部署与Nginx反向代理rewrite
java·前端·nginx
专业程序开发源10 分钟前
springboot生命故事书制作小程序65290-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·mysql·小程序·课程设计
鬓戈13 分钟前
Claude Code frontend-design 插件调研 与 Vue 旧系统风格一致性方案
前端·vue.js·人工智能
开开心心就好20 分钟前
以图搜图找重复图片,本地工具离线就能用
javascript·智能手机·ffmpeg·c#·ocr·word·音视频
IT_陈寒24 分钟前
SpringBoot自动配置的坑我帮你踩过了
前端·人工智能·后端
vx_Biye_Design27 分钟前
springboot角色扮演服务平台65161-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·python·spring·课程设计
企业数字化笔记29 分钟前
视频局部合成怎么做得自然?掩膜修复、边缘羽化、时序稳定与背景替换
java·javascript·音视频
vx_Biye_Design38 分钟前
springboot咖啡厅顾客点单管理系统12080-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·spring·课程设计·express
其实防守也摸鱼1 小时前
网安自测题:掌握核心知识点的实用练习
linux·运维·服务器·前端·数据库·sql·xss