Vue3 + Vite 中使用 Lodash-es 的防抖 debounce 详解

发布于:2025-06-09 ⋅ 阅读:(18) ⋅ 点赞:(0)

Vue3 + Vite 中使用 Lodash-es 的防抖(debounce)详解

在 Vue3 + Vite 项目中,debounce 是 lodash-es 中最常用的功能之一,它可以帮助我们优化高频事件的处理。下面我将详细讲解 debounce 的使用方法,并提供一个完整的示例。

Debounce 核心概念

防抖(debounce) 是一种优化高频操作的技术。它会将多次连续的操作合并为一次,确保函数在指定时间间隔内只执行一次。

适用场景

  • 搜索框输入建议

  • 窗口大小调整事件

  • 滚动事件处理

  • 表单验证

在 Vue3 中使用 Debounce

安装 lodash-es

bash

复制

下载

npm install lodash-es

Debounce 参数详解

基本语法

javascript

复制

下载

const debouncedFunc = debounce(func, [wait=0], [options={}])

参数说明

  • func (Function): 要防抖的函数

  • [wait=0] (number): 延迟的毫秒数

  • [options={}] (Object): 选项对象

  • [options.leading=false] (boolean): 指定在延迟开始前调用

  • [options.trailing=true] (boolean): 指定在延迟结束后调用

  • [options.maxWait] (number): 设置 func 允许被延迟的最大时间

选项说明

  1. leading: true (立即执行模式)

    • 第一次触发时立即执行

    • 后续在等待时间内触发不会执行

    • 等待时间结束后再次触发会再次立即执行

  2. trailing: true (延迟执行模式 - 默认)

    • 第一次触发后开始计时

    • 在等待时间内再次触发会重置计时器

    • 等待时间结束后执行最后一次操作

  3. maxWait (最大等待时间)

    • 确保函数在指定时间内至少执行一次

    • 即使连续触发也不会超过这个时间间隔

在 Vue3 中使用 Debounce 的最佳实践

1. 在 setup 中创建防抖函数

javascript

复制

下载

import { debounce } from 'lodash-es'

// 在 setup 中创建防抖函数
const debouncedFunction = debounce(() => {
  // 你的逻辑
}, 300)

2. 组件卸载时取消防抖

javascript

复制

下载

import { onUnmounted } from 'vue'

onUnmounted(() => {
  debouncedFunction.cancel()
})

3. 在模板中使用

vue

复制

下载

<input @input="debouncedSearch" />

4. 处理带参数的函数

javascript

复制

下载

const debouncedSearch = debounce((searchTerm) => {
  // 使用 searchTerm
}, 500)

// 在事件处理中
const handleInput = (e) => {
  debouncedSearch(e.target.value)
}

5. 使用立即执行模式(leading)

javascript

复制

下载

const handleClick = debounce(() => {
  // 处理点击
}, 1000, { leading: true, trailing: false })

注意事项

  1. 避免重复创建:不要在每次渲染时创建新的 debounce 函数,否则会失去防抖效果

  2. 组件卸载时取消:防止内存泄漏和意外执行

  3. 合理设置等待时间

    • 搜索建议:200-500ms

    • 窗口调整:100-300ms

    • 按钮点击:1000ms(防止重复提交)

  4. 与 async/await 一起使用

    javascript

    复制

    下载

    const debouncedAsync = debounce(async (param) => {
      const result = await fetchData(param)
      // 处理结果
    }, 300)

这个示例展示了在 Vue3 + Vite 项目中如何有效地使用 lodash-es 的 debounce 功能,涵盖了多种使用场景和配置选项。

<template>
  <div class="container">
    <h1>Lodash-es Debounce 使用演示</h1>
    
    <div class="input-group">
      <label>搜索输入 (500ms 防抖):</label>
      <input 
        type="text" 
        v-model="searchTerm" 
        @input="handleSearchInput"
        placeholder="输入搜索关键词..."
      />
      <div class="search-result">搜索结果: {{ searchResults }}</div>
    </div>
    
    <div class="resize-group">
      <div class="resize-box" :style="{ width: boxWidth + 'px' }">
        调整窗口大小查看效果
      </div>
      <p>窗口大小: {{ windowSize.width }} x {{ windowSize.height }}</p>
    </div>
    
    <div class="button-group">
      <button @click="handleButtonClick">快速点击我 (防抖处理)</button>
      <p>点击次数: {{ clickCount }}</p>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { debounce } from 'lodash-es'

// 搜索相关状态
const searchTerm = ref('')
const searchResults = ref('')

// 防抖处理搜索输入
const handleSearchInput = debounce(() => {
  searchResults.value = `正在搜索: "${searchTerm.value}"...`
  console.log('执行搜索:', searchTerm.value)
}, 500)

// 窗口大小相关状态
const windowSize = ref({ width: window.innerWidth, height: window.innerHeight })

// 防抖处理窗口大小变化
const handleResize = debounce(() => {
  windowSize.value = {
    width: window.innerWidth,
    height: window.innerHeight
  }
  console.log('窗口大小更新:', windowSize.value)
}, 300)

// 监听窗口大小变化
onMounted(() => {
  window.addEventListener('resize', handleResize)
})

// 组件卸载时移除监听器
onUnmounted(() => {
  window.removeEventListener('resize', handleResize)
})

// 按钮点击相关状态
const clickCount = ref(0)

// 防抖处理按钮点击(带立即执行选项)
const handleButtonClick = debounce(() => {
  clickCount.value += 1
  console.log('按钮点击处理', clickCount.value)
}, 1000, { leading: true, trailing: false })
</script>

<style>
.container {
  max-width: 800px;
  margin: 0 auto;
  padding: 2rem;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  background: linear-gradient(135deg, #f5f7fa, #e4edf9);
  min-height: 100vh;
  border-radius: 12px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}

h1 {
  color: #2c3e50;
  text-align: center;
  margin-bottom: 2rem;
  border-bottom: 2px solid #3498db;
  padding-bottom: 1rem;
}

.input-group, .resize-group, .button-group {
  background: white;
  padding: 1.5rem;
  border-radius: 10px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
  margin-bottom: 2rem;
}

label {
  display: block;
  margin-bottom: 0.5rem;
  font-weight: 600;
  color: #34495e;
}

input {
  width: 100%;
  padding: 0.8rem;
  border: 1px solid #ddd;
  border-radius: 6px;
  font-size: 1rem;
  margin-bottom: 1rem;
  transition: border 0.3s;
}

input:focus {
  border-color: #3498db;
  outline: none;
  box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2);
}

.search-result {
  padding: 1rem;
  background-color: #e3f2fd;
  border-radius: 6px;
  font-weight: 500;
  color: #2c3e50;
}

.resize-box {
  height: 150px;
  background: linear-gradient(45deg, #3498db, #9b59b6);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.2rem;
  font-weight: bold;
  border-radius: 8px;
  margin-bottom: 1rem;
  transition: width 0.3s ease;
}

p {
  color: #7f8c8d;
  font-size: 0.95rem;
}

button {
  background: #3498db;
  color: white;
  border: none;
  padding: 0.8rem 1.5rem;
  border-radius: 6px;
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.3s, transform 0.2s;
  display: block;
  width: 100%;
  max-width: 300px;
  margin: 0 auto;
}

button:hover {
  background: #2980b9;
}

button:active {
  transform: translateY(2px);
}

.button-group p {
  text-align: center;
  margin-top: 1rem;
  font-size: 1.1rem;
  font-weight: bold;
  color: #2c3e50;
}
</style>