DuckBlog

Duck Blog

唐如飞

( ^∀^)/欢迎\( ^∀^)

79 文章数
14 评论数

VUE3+TS+VITE自定义防抖指令

tangrufei
2023-12-15 / 0 评论 / 242 阅读 / 0 点赞

废话不多说直接上代码

防抖工具类

/**
 * 创建一个防抖函数。
 * 
 * @param {Function} fn - 需要防抖的函数。
 * @param {number} delay - 防抖延迟时间,单位毫秒。
 * @return {Object} 包含防抖函数和取消函数的对象。
 */
export function debounce<T extends (...args: any[]) => any>(fn: T, delay: number = 500) {
    let timeout: ReturnType<typeof setTimeout> | null = null;
  
    const debouncedFn = (...args: Parameters<T>) => {
      if (timeout) {
        clearTimeout(timeout);
      }
      timeout = setTimeout(() => fn(...args), delay);
    };
    return { debouncedFn };
  }

自定义防抖指令

vue3中有所不同 直接看代码

import { Directive, DirectiveBinding, watchEffect } from "vue";
import { debounce } from "@/utils/debounce";

/**
 * Vue 自定义指令,提供防抖功能。
 *
 * 使用方法:
 * 在元素上应用 v-debounce 指令,并传入一个对象,该对象包含:
 * - fn: 需要防抖的函数。
 * - event: 触发防抖的事件类型,可以是一个字符串或字符串数组。
 * - delay (可选): 防抖延迟时间,单位毫秒,默认为 500 毫秒。
 *
 * 示例:
 * <button v-debounce="{ fn: handleClick, event: ['click', 'mouseover'], delay: 300 }">Click me</button>
 */
const vDebounce: Directive = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    // 提取防抖设置
    const stopWatch = watchEffect(() => {
      const { fn, event, delay = 500 } = binding.value;
      // 校验 fn 和 event 属性
      if (typeof fn !== "function" || !event) {
        console.warn(
          'vDebounce expects an object with "fn" and "event" properties'
        );
        return;
      }

      // 移除已存在的防抖事件监听器
      removeDebounceListeners(el);

      // 支持单个事件或多个事件的数组
      const events = Array.isArray(event) ? event : [event];

      // 为每个事件添加防抖监听器
      el.__debouncedEvents__ = events.map((eventType) => {
        const debounceFn = debounce(fn, delay).debouncedFn;
        el.addEventListener(eventType, debounceFn);
        return { eventType, handler: debounceFn };
      });
    });
    // 在元素上存储停止函数,以便在 beforeUnmount 时调用
    el.__stopDebounceWatch__ = stopWatch;
  },
  beforeUnmount(el: HTMLElement) {
    removeDebounceListeners(el);
    if (el.__stopDebounceWatch__) {
      el.__stopDebounceWatch__();  // 停止 watchEffect
    }
  },
};

/**
 * 移除元素上所有防抖事件监听器。
 *
 *
 * @param {HTMLElement} el - 绑定指令的 DOM 元素。
 */
function removeDebounceListeners(el: HTMLElement) {
  if (el.__debouncedEvents__) {
    el.__debouncedEvents__.forEach(({ eventType, handler }) => {
      el.removeEventListener(eventType, handler);
    });
    // 清除存储的事件监听器信息
    delete el.__debouncedEvents__;
  }
}

export default vDebounce;

使用案例


<template>
  <h1>{{ msg }}</h1>
  <input v-debounce="{ fn: handleInput, event: 'input', delay: 3000 }" />
  <div class="card">
    <button type="button"  v-debounce="debounce">count is {{ count }}</button>
    <p>
      Edit
      <code>components/HelloWorld.vue</code> to test HMR
    </p>
  </div>

  <p>
    Check out
    <a href="https://vuejs.org/guide/quick-start.html#local" target="_blank">create-vue</a>, the official Vue + Vite
    starter
  </p>

  <p>
    Install
    <a href="https://github.com/vuejs/language-tools" target="_blank">Volar</a>
    in your IDE for a better DX
  </p>
  <p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import vDebounce from '@/directives/debounceDirectve'; //导入自定义指令函数

const handleInput = (event: { target: { value: any; }; }) => {
  console.log(event.target.value); // 或者您希望执行的其他操作
};
const count = ref(0)
const click = () => {
  console.log('click')
  debounce.value.delay=debounce.value.delay+1000
  count.value++;
}
const debounce = ref(
  { fn: click,
    event: 'click',
     delay: 2000 
    }
)
</script>
<style scoped>
.read-the-docs {
  color: #888;
}
</style>

文章不错,扫码支持一下吧~
上一篇 下一篇
评论
来首音乐
光阴似箭
今日已经过去小时
这周已经过去
本月已经过去
今年已经过去个月