我做过一个项目,里面有这么一个需求,当用户输入提现金额的时候,需要调用接口计算出对应的手续费。 怎么知道用户输完并确定好提现金额了呢?假设用户心里确定要提现的金额是2000,但是他一开始只输入了200,停顿了一会,又输入了个0,手抖了一下多输入了个0,现在输入框中是20000,这个用户定睛一看,呀多输入了个0,赶紧又删了个0,这会终于输入心中所想:2000。
怎么办?难道用户每输入一个数字都调用接口?
我的内心慌了,后端小伙伴会把我吊打的
防抖隆重登场!!
防抖(debounce)
事件被频繁触发的情况下,一定时间间隔内没有再次触发,该事件函数会执行一次,如果在时间间隔结束之前事件被再次触发,则重新延时执行。
心情复杂的我看到这概念性知识,依旧心情复杂。既然心情还是复杂,那不如看个例子复杂多一会~
<!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>Input</title>
</head>
<body>
<input type="text" id="input" />
</body>
<script>
const myInput = document.querySelector('input');
myInput.oninput = debounce(count, 1000); // 用户输入时触发防抖函数
/* 防抖函数 */
function debounce(fn, wait, ...args) {
let timer = null;
return function() {
const context = this;
// 当用户输入内容的时候,如果存在定时器,清除定时器。保证用户输入之后,如果wait间隔内仍然有输入,则不执行fn函数
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(context, args);
}, wait);
};
}
/* 处理一些需要防抖的工作 */
function count() {
console.log('获取手续费');
}
</script>
</html>
看看效果(๑•̀ㅂ•́)و✧
结合代码和效果图,我们可以看到,当用户不间断地输入内容,会不断清除上一个定时器并且生成新的定时器,等用户内容输入结束之后,间隔1000ms之后,控制台才会输出“获取手续费”。
这样就不会在用户每输入一个数字之后都调用一次接口。瞬间不慌了~
在另一个项目中,我需要实现一个比较常见的功能,页面滚动到底部的时候自动加载下一页数据。二话不说上手就给页面添加了滚动事件,接着眼拙!手抖!二愣子!似的把接口请求往里一放....页面一刷....一滚....突然背脊一阵凉风,后台老大哥:“你是在DDoS吗?!”
其实我内心想说:我只是想测一下滚动条事件是否监听成功了而已╥﹏╥...
还是回来好好地写一个判断页面是否滚动到底部的逻辑吧。
window.addEventListener('scroll', onScroll); // 监听滚动条事件
function onScroll() {
//真实内容的高度
const pageHeight = Math.max(document.body.scrollHeight, document.body.offsetHeight);
//视窗的高度
const viewportHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || 0;
//隐藏的高度
const scrollHeight = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
console.log('scroll');
if (pageHeight - scrollHeight - viewportHeight <= 0) {
console.log('底部');
}
}
当滚动到了底部,就开始下一页数据的请求。看似解决了这个问题,其实这样做是很消耗性能的,当用户在滚动的时候,浏览器会无时不刻地计算和判断页面是否已经滚动到底部。我们看代码运行之后的效果图:
这个时候我们就要把节流隆重推出来啦!!
节流(throttle)
一定时间间隔内持续触发事件,只会执行一次处理函数。
添加节流之后的代码:
window.addEventListener('scroll', throttle(onScroll, 1000)); // 监听滚动条事件
/* 节流函数 */
function throttle(fn, wait, ...args) {
let timer = null;
return function() {
const content = this;
if (!timer) {
timer = setTimeout(() => {
fn.apply(content, args);
timer = null;
}, wait);
}
};
}
function onScroll() {
//真实内容的高度
const pageHeight = Math.max(document.body.scrollHeight, document.body.offsetHeight);
//视窗的高度
const viewportHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || 0;
//隐藏的高度
const scrollHeight = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
console.log('scroll');
if (pageHeight - scrollHeight - viewportHeight <= 0) {
console.log('底部');
}
}
我们来看看效果:
是不是惊呆了~(≧∇≦)ノ
当用户滚动页面的时候,会触发节流函数生成定时器,在定时器倒计时结束之前,即使用户不断滚动页面,都不会生成新的定时器,在原定时器倒计时结束之后,会触发滚动函数输出"scroll",并且清除定时器,这时候用户接着滚动页面,就会生成新的定时器,重复以上操作。
ヾ(^▽^*)谢谢大家的阅读,我的能力有限,写的并不是很好,希望大家多多指教!!