vue中防抖和节流的多种使用方式——装饰器,指令,通用方法

理解

防抖:n秒内没有再次触发,则执行最后一次触发的事件
节流:n秒内多次触发只执行第一次,n秒后可再次执行,可以减少执行的次数

使用场景:

防抖:输入框搜索
节流:页面滚动,窗口大小调整,多次点击

ts装饰器

// 防抖
export function PromiseDebounce(time = 200, delayTime = 400) {
  return function (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor
  ) {
    const original = descriptor.value;
    const debounceFn = function () {
      let timer = null;
      const execFn = function (...args: any) {
        if (timer) clearTimeout(timer);
        timer = setTimeout(async () => {
          const data = await Promise.all([
            // @ts-ignore
            original.call(this, ...args),
            new Promise((resolve) => {
              setTimeout(resolve, time);
            }),
          ]);
          return data[0];
        }, time);
      };
      return execFn;
    };
    descriptor.value = debounceFn();
    return descriptor;
  };
}

/**
 * 网络请求节流装饰器,对网络请求进行锁操作,网络请求结束之后释放
 * @param time 等网络请求结束和设置时间完成之后释放节流
 * @param delayTime 延迟被装饰方法的触发时间
 */
export function PromiseThrottle(time = 200, delayTime = 500) {
  return function (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor
  ) {
    const original = descriptor.value;
    const throttleFn = function () {
      let status = '';
      const execFn = async function (...args: any) {
        if (status === 'ing') {
          return;
        }
        status = 'ing';
        try {
          const data = await Promise.all([
            // @ts-ignore
            original.call(this, ...args),
            new Promise((resolve) => {
              setTimeout(resolve, time);
            }),
          ]);
          return data[0];
        } finally {
          setTimeout(() => {
            status = '';
          }, delayTime);
        }
      };
      return execFn;
    };
    descriptor.value = throttleFn();
    return descriptor;
  };
}

// 使用
@PromiseThrottle(1000)
private funA() {}

vue2指令

// /directive/index.js
const customDirective = [
  {
    name: 'common-throttle',
    config: {
      /**
       * button节流指令 v-common-throttle:[事件名称]="[时间]"
       * v-common-throttle:click="3000"
       */
      inserted(el, binding) {
        const { arg: eventType = 'click', value = 1000 } = binding;
        el.addEventListener(eventType, () => {
          if (!el.disabled) {
            el.disabled = true;
            el.__commonThrottleTimer__ = setTimeout(() => {
              el.disabled = false;
              el.__commonThrottleTimer__ = null;
            }, value);
          }
        });
      },
      unbind(el) {
        el.__commonThrottleTimer__ && clearTimeout(el.__commonThrottleTimer__);
      }
    }
  },
  {
    name: 'common-debounce',
    config: {
      /**
       * button 防抖指令 v-common-debounce:[事件名称].[延迟时间]="[函数名]"
       * v-common-debounce:click.500="myfunction"
       * v-common-debounce:click.500="() => myfunction(val1, val2)"
       */
      bind(el, binding) {
        const eventName = binding.arg || 'click';
        const [, delay = 300] = binding.rawName.split('.');
        el.addEventListener(eventName, (e) => {
          el.__commonDebounceTimer__ && clearTimer(el.__commonDebounceTimer__);
          el.__commonDebounceTimer__ = setTimeout(() => {
            if (typeof binding.value === 'function') {
              binding.value(e);
            }
            clearTimer(el.__commonDebounceTimer__);
          }, delay);
        });
      },
      unbind(el) {
        clearTimer(el.__commonDebounceTimer__);
      }
    }
  }
];

export default function (Vue) {
  customDirective.forEach((item) => {
    const { name, config } = item;
    Vue.directive(name, config);
  });
}


// main.js
import registDirective from '@/directive/index.js';
registDirective(Vue);

通用方法

// /utils/index.js
/**
 * 防抖函数
 * @param {Function} fn - 执行的函数
 * @param {Number} wait - 时间,单位毫秒
 */
export function debounce(fn, wait) {
  let timer;
  return () => {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn();
    }, wait);
  };
}

/**
 * 节流函数
 * @param {Function} fn - 执行的函数
 * @param {Number} wait - 时间,单位毫秒
 */
export function throttle(fn, wait) {
  let interval;
  return function () {
    if (interval) {
      return;
    }
    fn(arguments);
    interval = setTimeout(() => {
      clearInterval(interval);
      interval = null;
    }, wait);
  };
}

// index.vue
@input="debounceChangeValue"

import { debounce } from '@/utils/index.js';

created() {
    this.debounceChangeValue = debounce(() => {
      this.changeValue();
    }, 1000);
}

有一个细节,clearInterval之后还给interval置为null,这是因为单纯的清除定时器,interval还是有值的,if(interval)就会为true。

function test() {
    const interval = setInterval(() => {
        console.log(1);
    }, 1000);
    // 4s之后清除定时器,并查看interval的值
    setTimeout(() => {
        clearInterval(interval);
        if (interval) {
            console.log('interval', interval);
        }
     }, 4000);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值