直接步入正题:
防抖和节流就是限制函数的执行次数
举个栗子:
<div class="box">
<input type="text">
<input type="submit" id="inputId">
</div>
<script>
const btn = document.getElementById('inputId');
btn.addEventListener('click', submit)
function submit() {
console.log('接口数据');
}
</script>
在用户点击的时候他会重复提交,所以就需要限制submit的执行次数
防抖:
在第一次触发事件时,不立即执行函数,而是给出一个期限值比如200ms,然后:
- 如果在2000ms内没有再次触发滚动事件,那么就执行函数
- 如果在2000ms内再次触发滚动事件,那么当前的计时取消,重新开始计时
效果:如果短时间内大量触发同一事件,只会执行一次函数。
<button>防抖</button>
<script>
let btn = document.querySelector("button")
function submit() {
console.log('请求数据');
}
function debounce(fn, time) {
var timer
return function () {
clearInterval(timer)
timer = setTimeout(fn, time)
}
}
btn.addEventListener("click", debounce(submit, 2000))
</script>
到了这一步防抖已经实现了
节流:
效果:如果短时间内大量触发同一事件,那么在函数执行一次之后,该函数在指定的时间期限内不再工作,直至过了这段时间才重新生效
<button>节流</button>
<script>
let btn = document.querySelector("button")
function submit() {
console.log('请求数据');
}
function throttle(fn, delay) {
var time1 = Date.now()
return function () {
var time2 = Date.now()
if (time2 - time1 > delay) {
fn()
time1 = Date.now()
} else {
console.log('正在请求中');
}
}
}
btn.addEventListener("click", throttle(submit, 2000))
</script>
这样就实现了函数的节流
vue中函数节流和防抖
第一步:定义公共防抖和节流函数
export default {
/**
* 函数防抖
* 触发事件后在n秒后执行,如果n秒内又触发事件,则重新计算时间
*/
debounce(fn, wait = 1000) {
let timer;
return function () {
let context = this;
let args = arguments;
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(context, args);
}, wait)
}
},
/**
* 函数节流
* 触发事件立即执行,但在n秒内连续触发则不执行
*/
throttle(fn, wait = 1000) {
let timer;
return function () {
if (timer != null) return;
let context = this;
let args = arguments;
fn.apply(context, args);
timer = setTimeout(() => {
timer = null;
}, wait);
}
},
}
注意:
防抖和节流函数中 return 的函数不能使用箭头函数,如果使用箭头函数则 this 就会指向 globalFunction,就会有问题
第二步:新建 Vue 组件
<template>
<div class="wrapper">
<div @click="btnDebounce('函数','防抖')">函数防抖</div>
<div @click="btnThrottle('函数','节流')">函数节流</div>
</div>
</template>
第三步:引用 globalFunction 并在 methods 中使用
<script>
import globalFunction from "../../utils/globalFunction";
export default {
name: "test",
methods: {
btnDebounce: globalFunction.debounce(function (str1, str2) {
console.log(str1, str2);
}, 2000),
btnThrottle: globalFunction.throttle(function (str1, str2) {
console.log(str1, str2);
}, 2000),
}
}
</script>
说明:
globalFunction 类的 debounce、throttle 返回的一个函数,就相当于
btnDebounce() {
let context = this;
let args = arguments;
console.log(this);
console.log(args);
}
所以可以拿到当前 this 和 arguments 参数,因为 argument 获取的是一个类似数组的对象,所以可以通过调用函数的 apply 方法来传递参数
TS+Vue3中使用
methods.ts
export const throttle = <T extends (...args: any[]) => void>(
func: T,
wait: number
) => {
let timer: NodeJS.Timeout | null = null;
return function (this: any, ...args: any[]) {
if (!timer) {
func.apply(this, args);
timer = setTimeout(() => {
timer = null;
}, wait);
}
} as T;
};
xxx.vue
import { throttle } from "@/utils/methods";
const itemClick = throttle(function () {
}, 2000);