防抖

定义:当一段时间内连续多次触发某事件时,只执行最后一次。如果在设置的间隔时间内又触发事件,则清除定时器重新计时。

案例:持续触发 scroll 事件时,不立即执行 handle 函数,当 1s 内没有再触发 click 事件时才执行 handle
代码:

用 addEventListener 添加防抖

created() {
  window.addEventListener('resize', this.debounce(this.fn, 500))
},
methods: {
  debounce (fn, wait) {
    let timer = null
    return () => {
      if (timer) {
        clearTimeout(timer)
      }
      timer = setTimeout(fn, wait)
    }
  },
  fn () {
    console.log(Math.random())
  }
}
复制代码

用 onClick 添加防抖
没有闭包,定时器也是唯一的,只能给一个按钮添加防抖
闭包的好处:不产生全局变量,可以复用

// 防抖方法从外面引入
<el-button @click="debounce(fn, 1000)">test</el-button>

// utils.js
Vue.prototype.debounce = function (fn, wait) {
  if (window.timer2) {
    clearTimeout(window.timer2)
  }
  window.timer2 = setTimeout(fn, wait)
}


// 防抖的方法在当前文件内
<el-button @click="debounce(fn, 1000)">test</el-button>

debounce (fn, wait) {
  if (this.timer) {
    clearTimeout(this.timer)
  }
  this.timer = setTimeout(fn, wait)
},
fn () {
  console.log(Math.random())
}
复制代码

闭包形式的:

// 防抖的方法从外面引入
Vue.prototype.yyy = (fn, delay = 1000) => {
  let timer = null
  return (...params) => {
    const context = this
    if (timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      fn.apply(context, params)
    }, delay)
  }
}

created() {
  this.zzz = this.yyy(this.fn)
}

<el-button @click="zzz(1)">test</el-button>


// 防抖的方法在当前页面内
// 给闭包传 fn 传不进去,是 undefined
复制代码

重点是要拿到 debounce 方法返回的那个 方法A,绑定事件的时候要绑定这个 方法A。

推荐使用方式:

  • 在外面用闭包形式写防抖,然后引入
  • 全局指令形式

全局指令形式具体代码:
directive/debounce.js

import { debounce } from '@/utils'

export default  {
  inserted: function(el, binding, vnode) {
    let [fn,wait,immediate,event = "click"] = binding.value
    el.addEventListener(event, debounce(
      fn,
      wait,
      immediate
    ).bind(vnode))
  }
} 
复制代码

directive/index.js

import debounce from './debounce'

const install = function (Vue) {
    Vue.directive('debounce', debounce)
}

debounce.install = install

export {
    debounce
}
复制代码

main.js

import {debounce} from './directive'

debounce.install(Vue)
复制代码

Test.vue

<el-button v-debounce="[fn]">test</el-button>

fn () {
  console.log(Math.random())
}
复制代码

节流

定义:当一段时间内连续多次触发某事件时,每个间隔时间内只能执行一次,过了间隔时间才能执行下一次。
案例:持续触发 scroll 事件时,不立即执行 handle 函数,每个 1s 执行一次 handle。
代码:

export const throttle = (fn: Function, delay = 2000) => {
  let preTime = Date.now()
  return (...params: any[]) => {
    const context = this
    let doTime = Date.now()
    if (doTime - preTime >= delay) {
      fn.apply(context, params)
      preTime = Date.now()
    }
  }
}