节流和防抖vue中使用

  • 防抖:你点击那一下开始,如果你继续没有停止还在继续的疯狂的点击,他就给你执行一次,直到你停止为了,然后再次点击就会执行第二次
  • 节流:你点击那一下开始,如果你继续没有停止还在继续的疯狂的点击,超过你指定的时间就继续执行第二次

防抖(debounce)

  • 触发高频事件后n秒内函数只会执行一次,如果在n秒内高频事件再次被触发,则重新计算时间。

简单的说也就是一定时间段的无论点击多少次,只会执行最后一次的调用。前面的会被清除

  1. 在methods中直接实现
debounce (func, delay = 1000, immediate = false) {
  //闭包
  let timer = null
  //不能用箭头函数
  return function () {
    if (timer) {
      clearTimeout(timer)
    }
    if (immediate && !timer) {
      func.apply(this,arguments)
    }
    timer = setTimeout(() => {
      func.apply(this,arguments)
    }, delay)
  }
},
  1. vue中引入使用
<template>
  <el-input v-model="text" @input="debounceInput" />
</template>

<script>
  export default {
    mounted () {
      this.debounceInput = this.debounce(this.handle, 1000,false)
    },
    data () {
      return {
        text: '',
        debounceInput: () => {},
      }
    },

    methods: {
      handle (value) {
        console.log(value)
      },

      debounce (func, delay = 1000, immediate = false) {
        let timer = null
        //不能用箭头函数
        return function () {
          //在时间内重复调用的时候需要清空之前的定时任务
          if (timer) {
            clearTimeout(timer)
          }
          //适用于首次需要立刻执行的
          if (immediate && !timer) {
            func.apply(this,arguments)
          }
          timer = setTimeout(() => {
            func.apply(this,arguments)
          }, delay)
        }
      },
    }
  }
</script>

节流(throttle)

  • 触发高频事件后,但在n秒内函数只会执行一次

简单的说也就是一定时间内的无论点击多少次,都只会执行第一次,其余的直接return

  1. utils.js中实现(时间戳版本)
export const throttle = (fn, delay = 1000) => {
  //距离上一次的执行时间
  let lastTime = 0
  return function () {
    let _this = this
    let _arguments = arguments
    let now = new Date().getTime()
    //如果距离上一次执行超过了delay才能再次执行
    if(now - lastTime > delay){
      fn.apply(_this,_arguments)
      lastTime = now
    }
  }
}
  1. vue中引入使用
<template>
  <el-input v-model="text" @input="throttleInput" />
</template>

<script>
  import {throttle} from '../utils'
  export default {
    name: 'throttle',
    data () {
      return {
        text: '',
      }
    },
    methods: {
      handle (value) {
        console.log(value)
      },

      throttleInput: throttle(function (...args) {
        this.handle(...args)
      })

    }

  }
</script>

节流的优化

上一次执行和下一次用户操作的时间差在delay内的话,这个操作就会被废弃,所以我们需要在这个时间段内生成一个timer去保证这个操作是会执行的,如果超过delay时间的话可以直接执行

  • utils.js
export const throttle = (fn, delay = 2000) => {
  let lastTime = 0, timer = null

  return function () {
    let _this = this
    let _arguments = arguments
    let now = new Date().getTime()
    clearTimeout(timer)
    // 判断上次触发的时间和本次触发的时间差是否小于delay,创建一个timer
    if (now - lastTime < delay) {
      timer = setTimeout(function () {
        lastTime = now
        console.log("执行器触发")
        fn.apply(_this, _arguments)
      }, delay)
    } else {
      // 否则可以直接执行
      lastTime = now
      console.log("直接触发")
      fn.apply(_this, _arguments)
    }
  }
}

另外一种

  • 用法差不多 仅参考
// 在utils.js中
export const debout = function throttle(fn, time) {
  //节流函数
  var last = 0
  return function () {
    var now = new Date().getTime()

    if (now - last >= time) {
      last = now
      fn.apply(this, arguments)
    }
  }
}


// 在vue中引入使用
// 在methods中直接实现
throttleInput: debout(function (...args) {
      this.sub(...args)
}, 2000),

第三方库对节流和防抖的实现(lodash)🔨

  • 安装lodash
# npm
npm install lodash --save

#yarn
yarn add lodash  

Vue中使用节流和防抖例子

  • throttling 方法 节流

要对事件进行节流处理方法非常简单,只需将要调用的函数包装在lodash_.throttle函数中即可。

<template>
  <button @click="throttledMethod()">Click me as fast as you can!</button>
</template>

<script>
import _ from 'lodash'

export default {
  methods: {
   // vue中的methods中声明,左侧变量,右侧函数的形式声明, 点击的时候触发,因为throttle返回的是一个函数。函数调用必须用 ()调用
    throttledMethod: _.throttle(() => {
      console.log('I get fired every two seconds!')
    },
      2000,
      {
        leading: true,
        trailing: false,
      }
    ), 
  }
}
</script>
  • throttle API走起

_.throttle(func, [wait=0], [options={}])

func (Function): 要节流的函数。

[wait=0] (number): 需要节流的毫秒数。

[options={}] (Object): 选项对象。

[options.leading=true] (boolean): 指定调用在节流开始前,默认true

[options.trailing=true] (boolean): 指定调用在节流结束后,默认true

  • debouncing 方法 防抖

尽管节流在某些情况下很有用,但一般情况我们经常使用的是防抖。 防抖实质上将我们的事件分组在一起,并防止它们被频繁触发。 要在Vue组件中使用节流,只需将要调用的函数包装在lodash_.debounce函数中。


<template>
  <button @click="throttledMethod()">Click me as fast as you can!</button>
</template>

<script>
import _ from 'lodash'

export default {
  methods: {
    throttledMethod: _.debounce(() => {
      console.log('I only get fired once every two seconds, max!')
    },
      2000,
      {
        leading: true,
        trailing: false,
      }
    ),  
  }
}
</script>
  • debounce API走起

_.debounce(func, [wait=0], [options={}])

func (Function): 要防抖动的函数。

[wait=0] (number): 需要延迟的毫秒数。

[options={}] (Object): 选项对象。

[options.leading=false] (boolean): 指定在延迟开始前调用,默认false

[options.maxWait] (number): 设置 func 允许被延迟的最大值。

[options.trailing=true] (boolean): 指定在延迟结束后调用,默认true

  • 结合element-ui在查询中使用节流
 <!-- 按钮 -->
 <el-button @click="handleClick(item.event)">
 	点击
 </el-button>
// 注意:使用lodash必须通过这种方式,throttle的箭头函数,里面的this反而为undefined
// 必须通过function(event),里面的this才是指向vue

handleClick: _.throttle(function(event) {
    this.$emit("handleClick", event);
    console.log("lodash");
},
 4000,
 {
 leading: true,
 trailing: false,
 }
), 

vue 防抖节流函数——组件封装 🚀

防抖(debounce)

所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。

节流(throttle)

所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。

就相当于,一个水龙头在滴水,可能一次性会滴很多滴,但是我们只希望它每隔 500ms 滴一滴水,保持这个频率。即我们希望函数在以一个可以接受的频率重复调用。

  • vue 封装utils.js
const debounce = (func, time, isDebounce, ctx) => {
  var timer, lastCall, rtn
  //防抖函数
  if (isDebounce) {
    rtn = (...params) => {
      if (timer) clearTimeout(timer)
      timer = setTimeout(() => {
        func.apply(ctx, params)
      }, time)
    }
  } else {
    //节流函数
    rtn = (...params) => {
      const now = new Date().getTime()
      if (now - lastCall < time && lastCall) return
      lastCall = now
      func.apply(ctx, params)
    }
  }
  return rtn
}

export default {
  name: 'Debounce',
  abstract: true,
  props: {
    time: {
      type: Number,
      default: 800,
    },
    events: {
      type: String,
      default: 'click',
    },
    isDebounce: {
      type: Boolean,
      default: false,
    },
  },
  created() {
    this.eventKeys = this.events.split(',')
    this.originMap = {}
    this.debouncedMap = {}
  },
  render() {
    const vnode = this.$slots.default[0]
    this.eventKeys.forEach(key => {
      const target = vnode.data.on[key]
      if (target === this.originMap[key] && this.debouncedMap[key]) {
        vnode.data.on[key] = this.debouncedMap[key]
      } else if (target) {
        this.originMap[key] = target
        this.debouncedMap[key] = debounce(target, this.time, this.isDebounce, vnode)
        vnode.data.on[key] = this.debouncedMap[key]
      }
    })
    return vnode
  },
}
  • 然后我们在main.js入口文件里面全局注册一下
import Debounce from '@/config/debounce'
 
Vue.component('Debounce',Debounce)
  • 组件中使用方法

当是isDebounce时表示是防抖函数,!isDebounce是节流函数,time是执行时间间隔

<!--当是isDebounce时表示是防抖函数,!isDebounce是节流函数,time是执行时间间隔-->
<Debounce :time='1000' isDebounce>
    <button  @click='btn'>btn</button>
</Debounce>
posted @ 2022-05-22 01:43  天使阿丽塔  阅读(754)  评论(0编辑  收藏  举报