自定义指令简介及用法(vue3)

一介绍

防抖与节流,应用场景有很多,例如:禁止重复提交数据的场景、搜索框输入搜索条件,待输入停止后再开始搜索。

防抖

点击button按钮,设置定时器,在规定的时间内再次点击会重置定时器重新计时,在规定的时间没有再次点击才执行相关函数。
规定时间内最后一次点击有效。


节流

点击button按钮,执行相关函数。设置定时器,在规定的时间内连续点击均无效,定时器过后,可以再次点击。
规定时间内可点击一次(第一次点击有效)。

案例-防抖

Vue项目中使用自定义指令实现(按钮)防抖功能。

应用场景:搜索框输入搜索条件,待输入停止后再开始搜索。

案例-节流

Vue项目中使用自定义指令实现(按钮)节流功能。

应用场景:click事件,禁止重复提交数据的场景。

二 使用

debounceThrottle.ts

import { App, Directive } from "vue"

// 防抖指令
export const debounce: Directive = {
  mounted(el: HTMLElement, binding) {
    if (!validateBinding(binding, "debounce")) return

    let timer: number | null = null
    const eventType = binding.arg || "click"
    const delay = binding.value.time || 300
    const handler = binding.value.handler
    const args = binding.value.args || [] // 参数数组

    const listener = () => {
      if (timer) clearTimeout(timer)
      timer = window.setTimeout(() => {
        handler(...args) // 执行方法并传递参数
      }, delay)
    }

    el.addEventListener(eventType, listener)
    ;(el as any).__debounce_listener__ = listener // 保存监听器以便卸载时移除
  },
  unmounted(el: HTMLElement) {
    removeListener(el, "__debounce_listener__", "debounce")
  }
}

// 节流指令
export const throttle: Directive = {
  mounted(el: HTMLElement, binding) {
    if (!validateBinding(binding, "throttle")) return

    let lastTime = 0
    const eventType = binding.arg || "click"
    const delay = binding.value.time || 300
    const handler = binding.value.handler
    const args = binding.value.args || [] // 参数数组

    const listener = () => {
      const now = Date.now()
      if (now - lastTime >= delay) {
        handler(...args) // 执行方法并传递参数
        lastTime = now
      }
    }

    el.addEventListener(eventType, listener)
    ;(el as any).__throttle_listener__ = listener // 保存监听器以便卸载时移除
  },
  unmounted(el: HTMLElement) {
    removeListener(el, "__throttle_listener__", "throttle")
  }
}

// 校验绑定值
function validateBinding(binding: any, directiveName: string): boolean {
  if (
    !binding.value ||
    typeof binding.value.handler !== "function" ||
    (binding.value.args && !Array.isArray(binding.value.args))
  ) {
    console.warn(
      `[v-${directiveName}]: Expected an object with a "handler" function, optional "time" (number), and optional "args" (array). Example: { time: 300, handler: () => {...}, args: [arg1, arg2] }`
    )
    return false
  }
  return true
}

// 移除事件监听器
function removeListener(el: HTMLElement, listenerKey: string, directiveName: string) {
  const eventType = el.getAttribute(`v-${directiveName}-event`) || "click"
  const listener = (el as any)[listenerKey]
  if (listener) {
    el.removeEventListener(eventType, listener)
  }
}

index.ts

import { debounce, throttle } from "./debounceThrottle"

export default {
  debounce,
  throttle,
}

main.ts

import { createApp } from "vue"
import App from "./App.vue"
import directives from "@/directives"



const app = createApp(App)

// 批量注册自定义指令
Object.keys(directives).forEach((directiveName) => {
  app.directive(directiveName, directives[directiveName])
})

使用

 <el-button
          type="primary"
          v-if="hasAuth"
          v-throttle:click="{ time: 500, handler: onSaveAndAuth }"
          >保存并验证</el-button
        >



const onSaveAndAuth = () => {
  contactsFormRef.value?.validate((valid) => {
    valid && saveContact(1)
  })
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值