1 防抖和节流函数
js
/**
* 防抖原理:一定时间内,只有最后一次操作,再过wait毫秒后才执行函数
* 防抖又分为立即执行和延迟执行
* - 立即执行:点击第一次就会执行,后续指定时间内的点击不会生效
* - 延迟执行:指定时间内不再进行点击,也就是过了这个指定时间,才会执行一次函数,前面的n次点击不会生效
*
* @param {Function} func 要执行的回调函数
* @param {Number} wait 延时的时间
* @param {Boolean} immediate 是否立即执行
* @return null
*/
function debounce(func, wait = 500, immediate = true) {
let timer = null;
return function (...args) {
// 如果存在定时器,则还处在等待期间,则清除定时器,重新开始计算时间
if (timer) {
clearTimeout(timer);
}
if (immediate) {
// 如果是立即执行,则第一次进入的时候,定时器为空,会立即执行一次,然后立即开启一个定时器
// 短时间内触发第二次时,定时器是不为空的,那么就不会执行,只有等定时器走完,清除了timer,才会再次执行
// 这样也就实现了第一次点击立即执行,后面过了指定时间,定时器为空,才会再次执行
// 注意:需要注意参数和this绑定的处理
if (!timer) {
typeof func === "function" && func.apply(this, args);
}
timer = setTimeout(() => {
timer = null;
}, wait);
} else {
// 设置定时器,定时器正常走完才会执行方法,也就是指定时间内没有再次触发,才会执行
timer = setTimeout(() => {
typeof func === "function" && func.apply(this, args);
}, wait);
}
};
}
/**
* 节流原理:当持续触发事件时,有规律地每隔一个时间间隔执行一次事件处理函数
* 适用于大量触发事件的场景,譬如监听滚动事件、鼠标滑动事件等
*
* @param {Function} func 要执行的回调函数
* @param {Number} wait 延时的时间
* @param {Boolean} immediate 是否立即执行
* @return null
*/
function throttle(func, wait = 500, immediate = true) {
let isCanExecute = true; // 是否可以执行函数
return function (...args) {
if (immediate) {
// 立即执行
if (isCanExecute) {
isCanExecute = false;
typeof func === "function" && func.apply(this, args);
setTimeout(() => {
isCanExecute = true;
}, wait);
}
} else {
// 延迟执行
// 第一次触发,处于可以执行的状态,会进入判断,状态设置为不可以执行,同时开启定时器,定时器当中会执行函数,执行完函数,会重置状态为可以执行
// 第二次触发时,处于不可执行状态,不会进入判断,只有当内部的定时器走完后,状态设置为了true,才会进入判断,才会开启定时器
if (isCanExecute) {
isCanExecute = false;
setTimeout(() => {
typeof func === "function" && func.apply(this, args);
isCanExecute = true;
}, wait);
}
}
};
}
2 Vue当中的写法
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Vue</title>
</head>
<body>
<div id="app">
<button @click="handleDebounceClick(1, 2)">按钮-防抖</button>
<button @click="handleThrottleClick(1, 2)">按钮-节流</button>
</div>
</body>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.min.js"></script>
<!-- utils.js文件的内容就是上述的两个函数 -->
<script src="../utils.js"></script>
<script>
new Vue({
el: "#app",
data: {
num: 123,
},
methods: {
// 防抖
handleDebounceClick: debounce(function (data1, data2) {
console.log(this.num); // 读取data当中的数据
console.log(data1); // 读取参数1
console.log(data2); // 读取参数2
}),
// 节流
handleThrottleClick: throttle(function (data1, data2) {
console.log(this.num); // 读取data当中的数据
console.log(data1); // 读取参数1
console.log(data2); // 读取参数2
}),
},
});
</script>
</html>
3 React当中的写法
js
// utils.js文件的内容就是上述的两个函数
import { debounce, throttle } from "../utils.js";
function Demo(props) {
// 防抖
const handleDebounceClick = debounce((data1, data2) => {
console.log(data1); // 读取参数1
console.log(data2); // 读取参数2
});
// 节流
const handleThrottleClick = throttle((data1, data2) => {
console.log(data1); // 读取参数1
console.log(data2); // 读取参数2
});
return (
<React.Fragment>
<button onClick={() => handleDebounceClick(1, 2)}>按钮-防抖</button>
<button onClick={() => handleThrottleClick(1, 2)}>按钮-节流</button>
</React.Fragment>
);
}