关于防抖

  • 概念:触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。
  • 思路:每次触发事件的时候,清除定时器,然后从新设置新的定时器。

如何实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 定义一个定时器
let timer = null;
let value = "hello";
function clickBut() {
let timer = null;
// 创建一个闭包,保存一个标记用来存放定时器的返回值
return function () {
clearTimeout(timer)
timer = setTimeout(() => {
console.log(value);
}, 1000);
};
}
// 只能通过document.getElementById监听点击事件 button 上直接挂载 clickBut 函数,不会回调闭包中的函数
document.getElementById("button1").addEventListener("click", clickBut);
document.getElementById("button2").addEventListener("click", clickBut);

借助定时器就可以实现多次点击只会对最后一次点击生效

关于节流

  • 概念:高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率。
  • 思路:每此触发事件时判断是否定时器已满,满则重新定时,否则不做任何事。

如何实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let value = "hello";
// 设置一个变量判断点击是否生效
function clickBut() {
let canRun = true; // 通过闭包保存一个标记
return function (parmas) {
if (!canRun) return; // 在函数开头判断标记是否为true,不为true则return
canRun = false; // 立即设置为false
setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中
console.log(value, parmas);
// 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉
canRun = true;
}, 500);
};
}
// 只能通过document.getElementById监听点击事件 button 上直接挂载 clickBut 函数,不会回调闭包中的函数
document.getElementById("button1").addEventListener("click", clickBut(1));
document.getElementById("button2").addEventListener("click", clickBut(2));

看到这里我们可以通过代码就可以发现,防抖和节流都会阻止用户部分操作。区别就是在一定的时间内多次操作,防抖只会对最后一次操作生效,而节流每过一定时间都会对生效一次操作。
应用:

  • 防抖:一般应用在只搜集用户最后一次操作:如用户多次点击按钮,多次提交表单等。
  • 节流:一般应用在用户频繁多次操作中起到限制请求次数:如用户频繁刷新列表等。

怎么通过vue全局指令完成防抖和节流

在vue中有很多地方都会用到防抖和节流,防抖和节流的实现很见到。但如果在每个用到的地方都去写这写方法,那无疑是不明智的行为

vue3中的写法

防抖

utils/derectives/debounce.js 注册插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 注册插件
export default (Vue) => {
Vue.directive("debounce", {
created(el, fn) {
// 监听点击事件,回调函数必须添加 () => ;不然会立即执行
el.addEventListener('click', () => clickHandler(fn))
},
unmounted(el) {
// 组件卸载时移除监听事件
el.removeEventListener('click', clickHandler)
}
})
}
let timer = null;
// 点击事件的回调函数
function clickHandler(fn) {
// 创建一个闭包,保存一个标记用来存放定时器的返回值
let timer = null;
return function () {
console.log("11213123", timer);
clearTimeout(timer);
timer = setTimeout(() => {
fn && fn.value();
}, 4000)
}
}

xxx.vue 中使用

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<div>
<button v-debounce="() => debounceHandler(1)">按钮1</button>
<button v-debounce="() => debounceHandler(2)">按钮2</button>
</div>
</template>
<script setup>
// 点击回调函数
const debounceHandler = (id) => {
console.log(id)
}
</script>
节流

utils/derectives/debounce.js 注册插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 注册插件
export default (Vue) => {
Vue.directive("throtTleback", {
created(el, fn) {
// 监听点击事件,回调函数必须添加 () => ;不然会立即执行
el.addEventListener('click', () => clickHandler(fn))
},
unmounted(el) {
// 组件卸载时移除监听事件
el.removeEventListener('click', clickHandler)
}
})
}
// 点击事件的回调函数
function clickHandler(fn) {
// 创建一个闭包,保存一个标记用来存放定时器的返回值
let isCanClick = true;
return function () {
if (!isCanClick) return;
isCanClick = false;
setTimeout(() => {
fn && fn.value();
isCanClick = true;
}, 1000)
}
}

xxx.vue 中使用

1
2
3
4
5
6
7
8
9
10
11
12
<template>
<div>
<button v-throtTleback="() => debounceHandler(1)">按钮1</button>
<button v-throtTleback="() => debounceHandler(2)">按钮2</button>
</div>
</template>
<script setup>
// 点击回调函数
const debounceHandler = (id) => {
console.log(id)
}
</script>

感谢观看,如果对你有帮助可以关注本站,龙小亦在此谢过了