这篇文章主要讲解了“vue中使用闭包失效怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“vue中使用闭包失效怎么解决”吧!
1. 出现问题
防抖/节流使用无效,(例如防抖,按钮点击多次依旧执行多次)
----> 查看是闭包无效,定义的局部变量依旧为初值
----> 没有相应清除定时器
<el-button @click="btn1">按 钮1</el-button> <el-button @click="debounce(btn2)">按 钮2</el-button> </template> <script setup lang="ts"> // 以下方法调用不生效 const btn1 = () => { debounce(() => { console.log('点击了') }, 1000)() } const btn2 = () => { console.log('点击了'); } </script>
2. 问题原因
直接调用了防抖函数
原因:这个和vue的事件绑定原理有关。如果直接在函数体内部使用的话,结果就是,一个匿名的立即执行函数来进行执行。由于每次触发点击事件都会返回一个新的匿名函数, 就会生成一个新的函数执行期上下文(称之为执行栈),所以就会防抖/节流就会失效
3. 解决办法
<template> <el-button @click="btn">按 钮1</el-button> </template> <script setup lang="ts"> const btn = debounce(function() { console.log('点击了'); },500) </script>
4. 防抖节流函数
type DebouncedFn<T extends (...args: any[]) => any> = (this: ThisParameterType<T>, ...args: Parameters<T>) => void; type ThrottledFn<T extends (...args: any[]) => any> = (this: ThisParameterType<T>, ...args: Parameters<T>) => void; function debounce<T extends (...args: any[]) => any>(fn: T, delay: number, immediate = false): DebouncedFn<T> { let timer: number | null = null; return function(this: ThisParameterType<T>, ...args: Parameters<T>) { // if (timer !== null) clearTimeout(timer); timer && clearTimeout(timer) if (immediate) { const callNow = !timer; timer = setTimeout(() => { timer = null; }, delay); callNow && fn.apply(this, args); } else { timer = setTimeout(() => { fn.apply(this, args); }, delay); } }; } function throttle<T extends (...args: any[]) => any>(fn: T, delay: number, immediate = false): ThrottledFn<T> { let lastCall = 0; return function(this: ThisParameterType<T>, ...args: Parameters<T>) { const now = new Date().getTime(); // immediate 不为 true 时, 不立即执行 lastCall === 0 && !immediate && (lastCall = now) const diff = now - lastCall; if (diff >= delay) { lastCall = now; fn.apply(this, args); } }; } export { debounce, throttle }