用vue的自定义指令实现的防抖节流

209 阅读1分钟

v-debounce和v-throttle的实现


//防抖功能的实现
const debouce = function (func, wait, immdiate) {
       //对参数进行处理
       if (typeof func !== "function") return;
       if (typeof wait !== "number") {
           if (typeof wait === "boolean") {
               immdiate = wait;
           }
       }
       if (typeof wait === "undefined") {
           wait = 500;
       }
       if (typeof immdiate === "undefined") {
           immdiate = false;
       }
       let timer = null,
           result;

       return function proxy(...arg) {
           let self = this;
           let now = immdiate && !timer ? true : false;
           //清除定时器
           clearTimeout(timer);
           timer = setTimeout(function () {
               timer = null;
               //执行func的时候确保this是Dom元素,并且闯进去的参数有事件对象
               result = !immdiate ? func.call(self, ...arg) : null;
           }, wait);
           result = now ? func.call(self, ...arg) : null;
           return result
       };
   };
   //节流功能的实现
   const throttle = function throttle(func, interval) {
       //对参数初始化
       if (typeof func !== "function") return;
       if (typeof interval === "undefined") {
           interval = 500;
       }
       let pre = 0, //上次触发的时间
           timer = null;
       return function (...args) {
           let now = new Date(),
               self = this;
           let remaining = interval - (now - pre);
           //两次触发的时间间隔大于500ms==》立即执行
           if (remaining <= 0) {
               clearTimeout(timer);
               timer = null; //让下次如果没有超过500能实行定时器
               pre = now;
               func.call(self, ...args);
           } else if (!timer) {
               //两次触发时间间隔小于500ms==》
               timer = setTimeout(() => {
                   clearTimeout(timer); //如果间隔小于500ms的等待时间恰好有触发了一次,清除定时器
                   timer = null;
                   pre = new Date();
                   func.call(self, ...args);
               }, remaining);
           }
       };
   };
   
   let config = {
       bind(el, binding) {
           let wait = 200,
               val = binding.value,
               immediate = false,
               func,
               type = 'click',
               params = [],
               handle = binding.name === 'debounce' ? debouce : throttle
           if (val == null) return
           if (typeof val !== 'function' && typeof val !== 'object') return
           if (binding.arg) {
               wait = + binding.arg;
           }

           if (binding.modifiers && binding.modifiers.immdiate) immediate = binding.modifiers.immdiate;
           if (typeof val === 'function') {
               func = val;
           }
           if (typeof val === 'object') {
               func = val.func || function () { };
               type = val.type || 'click';
               params = val.params || []
           }
           el.$type = type;
           el.$handle = handle(function proxy(arg) {
               return func.call(this, ...params.concat(arg))
           }, wait, immediate)
           el.addEventListener(el.$type, el.$handle)
           
           //判断有没有传递wait,immdiate,type.params,func
       },
       unbind(el) {
           el.removeEventListener(el.$type, el.$handle)

       }
   }
   Vue.directive('debounce', config)
   Vue.directive('throttle', config)

使用

<template>
 <div id="app">
    <button
     v-debounce:3000.immdiate="{
       func: fn,
       params: [2, 3],
       type: 'click',
     }"
   >
     点我呀
   </button>

   <button
     v-throttle:1000="{
       func: fn,
       params: [10, 20],
     }"
   >
     点我啊~~
   </button>
</div>
</template>
<script>
export default {
 name: "App",
 data() {
   return {
   };
 },
 methods: {
   fn(a, b) {
     console.log(a, b);
   },
 },

};
</script>