Vue2使用定时器和闭包实现防抖和节流函数。
将函数放入util.js中,供具体功能在methods中调用。<br/
参考文档:
- 如何在Vue中优雅的使用防抖节流
- 人类高质量JS防抖与节流机制
- Vue项目中使用防抖和节流
- vue2使用lodash中的防抖(debounce)函数
- 从函数节流与防抖浅析this指向问题、闭包问题
- this指向问题
文章目录
- 防抖函数实现 方式1:
- util: debounce代码
- 功能中调用
- 执行结果
- 防抖函数实现 方式2:
- 代码
- 功能中调用(存在错误)
- 校正后的正确调用
- 校正后的执行结果
- 节流函数实现
- 代码
- 调用
- 结果
防抖函数实现 方式1:
使用 this[fnName]()
util: debounce代码
let util = {};util.debounce = function (fnName, delay = 500){let timer = nullreturn function () {console.count('防抖函数执行')if(timer){clearTimeout(timer);}timer = setTimeout(()=>{this[fnName]();}, delay);}
}export default util;
功能中调用
<Button @click="clickMe">我是一个防抖的按钮</Button>
import util from "@/components/util";
export default {methods:{funcTest() {console.log('实际函数执行 start-----------')console.count('实际执行次数')},clickMe: util.debounce('funcTest', 500),},beforeDestroy() {this.clickMe = null;},
}
执行结果
通过gif可以看到,我点击了四次按钮,最后一次点击0.5秒后才实际执行函数。
防抖函数实现 方式2:
使用 fn.apply(this, arguments)
在网上的资料中,这种实现是最多的,但是把防抖函数放到util.js中,程序就会报错:起都起不来。
Uncaught TypeError: Cannot read properties of undefined (reading ‘funcTest’)
代码
util.debounce2 = function(fn, delay = 500) {let timer = null;return function() { // flag1console.count('防抖函数执行')console.log(fn)if (timer) {clearTimeout(timer);}timer = setTimeout(() => {fn.apply(this, arguments);}, delay);}
}clickMe : util.debounce2 (this.funcTest, 500),
功能中调用(存在错误)
clickMe: util.debounce2(this.funcTest, 500),
报错:
校正后的正确调用
研究了vue中调用lodash的防抖函数的实现方式给了我灵感,我个人把他粗浅的解释为: util.debounce2是一个“外地人”,它无法找到funcTest()
这个函数,当然,使用调用方中data中的任何一个变量也都会报错。所以需要使用clickDebounce
本地化一下。
clickDebounce: util.debounce2 ( function (){ // flag2this.funcTest()},500),funcTest() {console.log('实际函数执行 start-----------')console.count('实际执行次数')},/* clickMe: util.debounce2(this.funcTest, 500),*/clickMe (){this.clickDebounce()},
注意:代码 flag1和flag2中的 function(){}
不能替换为箭头函数()=>{}
,因为箭头函数没有this,还是会报undefined的错误。
校正后的执行结果
通过结果,可以看到:可以实现防抖
节流函数实现
每个一段时间执行一次函数。避免一个函数在短时间内多次执行
代码
util.throttle = function(fn, delay = 500) {let lastCall = 0;return function() {console.count('节流函数执行')const now = Date.now();if (now - lastCall < delay) {return;}lastCall = now;return fn.apply(this, arguments);;}
}
调用
clickThrottle: util.throttle(function () {this.funcTest()}, 1000),funcTest() {console.log('实际函数执行 start-----------')console.count('实际执行次数')},/* clickMe: util.debounce2(this.funcTest, 500),*/clickMe() {this.clickThrottle()},
结果
通过gif可知,尽管点击频率很快,但是实际函数每隔1秒执行一次。