抽象组件实现节流/防抖


节流/防抖

  • 节流:
    • 一个函数执行一次后,只有大于设定的执行周期后才会被执行第二次(点击事件)
    • 有个需要频繁触发的函数,出于优化性能角度,在规定时间内,只让函数触发的第一次生效后面不生效
  • 防抖:
    • 一个需要频繁触发的函数,在规定时间内,只让最后一次生效,前面不生效

Vue实现函数防抖组件

// 组件

const throttle = function (fn, wait = 50, isDebounce, ctx) {
  let timer
  let lastCall = 0
  return function (...params) {
    if (isDebounce) {
      if (timer) clearTimeout(timer)
      timer = setTimeout(() => {
        fn.apply(ctx, params)
      }, wait);
    } else {
      const now = new Date().getTime()
      if (now - lastCall < wait) return
      lastCall = now
      fn.apply(ctx, params)
    }
  }
}

export default {
  name: "Throttle",
  abstract: true,
  props: {
    time: Number,
    events: String,
    isDebounce: {
      type: Boolean,
      default: false
    }
  },
  created() {
    this.eventKeys = this.events.split(",")
    this.originMap = {}
    this.throttledMap = {}
  },
  render() {
    const vnode = this.$slots.default[0]
    this.eventKeys.forEach(key => {
      const target = vnode.data.on[key]
      if (target === this.originMap[key] && this.throttledMap[key]) {
        vnode.data.on[key] = this.throttledMap[key]
      } else if (target) {
        this.originMap[key] = target
        this.throttledMap[key] = throttle(target, this.time, this.isDebounce, vnode)
        vnode.data.on[key] = this.throttledMap[key]
      }
    });
    return vnode
  }
}
// 通过第三个参数 isDebounce来控制切换防抖节流
// 在 main.js 引入
import Throttle from "./Throttle"
Vue.component("Throttle", Throttle)

// 使用
<div id="app">
  <Throttle :timer="1000" events="click">
    <botton @click="onClick($event, 1)">click + 1 {{val}}</botton>
  </Throttle>
  <Throttle :timer="1000" events="click" :isDebounce="true">
    <botton @click="onAdd">click + 3 {{val}}</botton>
  </Throttle>
  <Throttle :timer="3300" events="mouseleave" :isDebounce="true">
    <botton @mouseleave.prevent="onAdd">click + 3 {{val}}</botton>
  </Throttle>
</div>

const app = new Vue({
  el: "#app",
  data() {
    return {
      val: 0
    },
    methods: {
      onClick($ev,val) {
        this.val = val
      },
      onAdd() {
        this.val += 3
      }
    }
  }
})

实现一个防抖函数

// 在第一次触发事件时,不立即执行,而是在给定的时间值后,如果没有再次触发就执行,如果触发了,就取消当前的计时,然后重新计时

/**
 * 
 * @param {Function} fn 需要防抖的函数
 * @param {Number} delay 毫秒,防抖时间值
 */
function debounce(fn, delay=300){
  let timer = null
  return () => {
    if(timer){
      clearTimeout(timer)
    }
    timer = setTimeout(fn, delay)
  }
}

实现一个节流函数

// 类似控制阀门定期开放的函数,即让函数执行一次后,在间隔的时间里暂时失效不能再次执行,等过了间隔时间又重新激活(相当于冷却时间)

/**
 * 
 * @param {Function} fn 需要节流的函数
 * @param {Number} delay 毫秒,节流间隔时间值
 */
function throttle(fn, delay=300) {
  let valid = true
  return () => {
    if(!valid) {
      // 休息时间,不执行函数
      return false
    }
    // 工作时间,执行函数,并且在间隔期间内把状态设为无效
    valid = false
    setTimeout(() => {
      fn()
      valid = true
    }, delay);
  }
}

防抖函数的图形化表述

  • 防抖函数

  • 防抖函数类似此安装,只要进度没到100%,重新点击安装按钮他就会从头开始安装,直到安装进度能达到100%的时候才会触发事件,否则就不会触发


  目录