❝之前在写Pick Color色卡这个案例的时候,考虑到的一个多次点击 copy 键的问题,遂查阅资料后实现了节流的思想,在此做一次记录。
❞
知识补充
1. 防抖是什么?
防抖是指在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则重新计时。
例如对于一个按钮,可以规定它在点击0.5s后再响应,若这0.5s内又被点击了,则重新计时,只要在0.5s内不再被点击就可以作出响应。
与防抖相关还有一个概念,那就是节流。
2. 节流是什么?
节流是指规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内这个事件被触发多次,只有一次能生效。
例如对于一个按钮,规定好它被多次点击的时候在一个单位时间内只能有一次响应。
3. 怎么实现函数防抖或者节流呢?
欸嘿,前面都提到了时间的问题,那是不是可以通过 setTimeout() 这个方法去实现呢?
是的╰(°▽°)╯
(1)手撕防抖函数
实现思想: 设置一个计时器,如果再次触发,我们会清空之前的定时器,重新生成一个定时器。
<button id="debounce">防抖(o゚v゚)</button>
<script>
window.onload = function() {
var myDebounce = document.getElementById("debounce");
myDebounce.addEventListener("click", debounce(sayDebounce));
}
// 防抖函数,fn参数为接着要处理调用的函数
function debounce(fn) {
// 创建定时器
let timeout = null;
return function() {
// 每次当用户再次点击的时候,用clearTimeout()把前一个定时器setTimeout()清除
clearTimeout(timeout);
// 然后创建一个新的 setTimeout,
// 如果用户还点击了的话,就不会执行 fn 函数
// 再点击就是重新计时
timeout = setTimeout(() => {
fn.call(this, arguments);
}, 1000);
};
}
function sayDebounce() {
// ... 有些需要防抖的工作
console.log("防抖成功(o゚v゚)/");
}
</script>
(2)手撕节流函数
实现思想: 通过判断是否到达单位时间来触发函数。
<button id="throttle">节流(o゚v゚)</button>
<script>
window.onload = function() {
var myThrottle = document.getElementById("throttle");
myThrottle.addEventListener("click", throttle(sayThrottle));
}
// 节流函数
function throttle(fn) {
// 通过闭包保存一个标记是否可以执行
var canRun = true;
return function() {
// 如果标记为 true则可以执行
if(!canRun) {
return;
}
// 将标记设置为 false,防止执行之前再被执行
canRun = false;
// 定时器
setTimeout( () => {
fn.call(this, arguments);
// 执行之后,重新将标志设置为 true
canRun = true;
}, 2000);
};
}
function sayThrottle() {
console.log("节流成功!(o゚v゚)/");
}
</script>
我的实际应用
在 Pick Color 里呢,有三个对应的 HEX / RGB / HSL 的按钮,我想实现的是用户点击按钮后,可以获得点击的对应的文本存储在剪切板中,如何这个展示栏会展示两秒的“copied!”字样。
->
所以我要解决的问题有两个:一是希望将用户点击0.5s再作出响应,防止多次点击多次响应;二是在“copied”字样的2s里让这个div不被点击,不做响应。
因而学习了防抖之后,我就设置了0.5s的时间间隔,希望避免用户的多次点击:
var colorHsl = document.getElementsByClassName("copy-hsl")[0];
colorHsl.addEventListener("click", debounce(sayDebounce))
function debounce(fn) {
let timeout = null;
return function() {
clearTimeout(timeout);
timeout = setTimeout(() => {
fn.call(this, arguments);
}, 500);
};
}
function sayDebounce(){
var pickColor = this.innerHTML;
copyToClipboard(pickColor);
this.innerHTML = "copied!"
var time = 0;
setTimeout(() => {
this.innerHTML = pickColor;
},2000);
}
第二个问题,我选择在“copied”字样出现之后给div设置一个class属性,将其pointer-events设置为null,也就是元素永远不会成为鼠标事件的target,也就不会触发click事件辽~
.no-click{
pointer-events: none;
}
参考链接
掘金 | jsliang | 2019 面试准备 - JS 防抖与节流
最后
节流和防抖是很常见的一个性能优化的点,我也在项目过程中学习到了这个知识点,在这篇文章作纪录,若是本文中有什么错误的地方,希望掘友们可以指正~♪(´▽`)
另附 Pick Color色卡项目的源代码: Pick Color源代码
本文使用 mdnice 排版