第三十七节:防抖、节流封装(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
相关推荐
三小河1 小时前
AI 对话 "打字机" 是怎么实现的?从 SSE 流式、Markdown 组件到 Nginx 防粘连
前端·人工智能·面试
by组态1 小时前
Ricon组态系统通信配置指南
前端·后端·物联网
可涵不会debug1 小时前
LangChain 文本分割器详解:字符分割、Token 分割、硬约束递归分割实战
java·前端·数据库
掘金挖土1 小时前
前端手摸手跑路之 AI 应用开发(四)
前端
LEE1 小时前
Agent 的控制权,为什么正在回到模型手里?
前端·后端
沃夫上校1 小时前
跨域这件事,其实浏览器在替你挡刀
前端·后端·nginx
十年一梦惊觉醒1 小时前
快手视频发布助手,全自动视频发布带货工具
开发语言·前端·javascript
Solara1 小时前
中文字体子集化实录:3.2MB → 200KB 的完整脚本、踩坑清单与三条反直觉经验
前端·css·架构
超人气王1 小时前
细说agent心跳机制--agentLoop循环机制中死循环处理,带你进一步了解agent工作底层原理
javascript·人工智能