搜索框每敲一个字母就发请求,既浪费流量也容易打爆接口。Vue3 里把防抖封装成自定义指令,页面只要在输入框上挂 v-debounce 即可,逻辑集中在指令里,代码复用度极高。

实现思路

指令 mounted 时给元素绑定 input 事件,回调内先 clearTimeout 再重新 setTimeout,只有停止输入超过指定毫秒才调用业务方法;指令卸载时 Vue 会自动解绑监听,无需手动清理。

指令定义

// src/directives/debounce.js
const debounce = {
    mounted(el, binding) {
        let timer = null;
        // v-debounce:500 中的 500 即延迟毫秒
        const delay = binding.arg ? Number(binding.arg) : 300;
        const handler = binding.value;

        el.addEventListener("input", () => {
            clearTimeout(timer);
            timer = setTimeout(() => {
                handler.call(el, el.value);
            }, delay);
        });
    }
};

export default {
    install(app) {
        app.directive("debounce", debounce);
    }
};

页面使用

<template>
    <!-- 停止输入 500ms 后触发 onSearch,参数为最新输入值 -->
    <input v-model="keyword" v-debounce:500="onSearch" />
</template>

<script setup>
import { ref } from "vue";

const keyword = ref("");
const onSearch = (val) => {
    console.log("触发搜索:", val);
    // 在此调用列表接口
};
</script>

扩展玩法

  • main.js 里 app.use(debouncePlugin) 注册后全项目可用;
  • 需要点击防抖时把监听事件名换为 click 即可;
  • 防抖不适用场景可用节流思路:固定周期内只触发一次。

小结

指令把 DOM 事件处理与业务解耦,一个 v-debounce 取代全项目到处 new 的 setTimeout,是 Vue3 工程化的常规优化点。