鸿蒙Next使用闭包实现点击事件防抖 原创 精华

auhgnixgnahz
发布于 2025-7-20 15:19
浏览
0收藏

点击事件的防连击(防止短时间内多次触发点击) 是非常常见的需求,核心目的是避免因用户快速多次点击导致的业务逻辑异常、重复操作或性能问题。例如:表单提交:如注册、登录、支付、评论发布等。若不防连击,可能导致多次提交相同数据。
解决事件的防连击,需要用到闭包,通过以下例子,了解一下闭包

作用域

通过两个for循环,比较一下

test(){
  console.log('---开始执行'+DateUtil.format(new Date().getTime(),'HH:mm:ss'))
  let index =0;
  for (index; index <10; index++) {
    setTimeout(()=>{
      console.log('---index:'+ index+' '+DateUtil.format(new Date().getTime(),'HH:mm:ss'))
    }, index*1000)
  }
}
///打印日志:
I     ---开始执行15:59:51.60
I     ---index:10 15:59:51.61
I     ---index:10 15:59:52.62
I     ---index:10 15:59:53.62
I     ---index:10 15:59:54.61
I     ---index:10 15:59:55.61
I     ---index:10 15:59:56.61
I     ---index:10 15:59:57.61
I     ---index:10 15:59:58.61
I     ---index:10 15:59:59.61
I     ---index:10 16:00:00.61
test2(){
  console.log('---开始执行'+DateUtil.format(new Date().getTime(),'HH:mm:ss.fff'))
  for (let index = 0; index < 10; index++) {
    setTimeout(()=>{
      console.log('---index:'+ index+' '+DateUtil.format(new Date().getTime(),'HH:mm:ss.fff'))
    }, index*1000)
  }
}
///打印日志:
I     ---开始执行16:00:07.114
I     ---index:0 16:00:07.116
I     ---index:1 16:00:08.115
I     ---index:2 16:00:09.114
I     ---index:3 16:00:10.115
I     ---index:4 16:00:11.115
I     ---index:5 16:00:12.114
I     ---index:6 16:00:13.115
I     ---index:7 16:00:14.115
I     ---index:8 16:00:15.114
I     ---index:9 16:00:16.115

1.for循环是同步执行的,会瞬间完成所有定时器注册,导致所有打印几乎同时执行,因此打印全局的index是遍历后的最终值
2.let关键字会创建块级作用域,每次循环的i都是独立的,因此test2函数打印的index不是最终值

闭包

闭包是指有权访问另一个函数作用域中的变量的函数。即使该函数已经执行完毕,其作用域内的变量也不会被销毁,而是会被闭包捕获并保留。
被闭包捕获的变量不会随外部函数的结束而销毁,而是会在闭包内部持续存在
闭包的基础用法举例:在这个例子中,sumClosure是一个闭包,它捕获了外部作用域中的initialValue变量,并在其内部使用这个变量来计算总和

let initialValue = 10;
let sumClosure = (value: number) => {
  return value + initialValue;
};
console.log(sumClosure(10)+''); // 输出 20

闭包的高级用法:闭包也可以用于更复杂的场景,比如作为其他函数的参数或返回值。例如,您可以创建一个函数,该函数接受一个参数,并返回一个基于该参数计算的闭包

function  sumClosure2(value1: number){
  return  (value2: number)=>{
     return value1+value2
  }
}
console.log(sumClosure2(10)(10)+''); // 输出 20

通过对闭包的基本了解,改造一下上面for循环的打印:

print(num:number){
  return ()=>{
    setTimeout(()=>{
      console.log('---index:'+ num+' '+DateUtil.format(new Date().getTime(),'HH:mm:ss.fff'))
    }, num*1000)
  }
}
test(){
  console.log('---开始执行'+DateUtil.format(new Date().getTime(),'HH:mm:ss.fff'))
  let index =0;
  for (index; index <10; index++) {
    this.print(index)()
  }
}
//或者 传参给内部方法
 print(){
    return (num:number)=>{
      setTimeout(()=>{
        console.log('---index:'+ num+' '+DateUtil.format(new Date().getTime(),'HH:mm:ss.fff'))
      }, num*1000)
    }
  }

  test(){
    console.log('---开始执行'+DateUtil.format(new Date().getTime(),'HH:mm:ss.fff'))
    let index =0;
    for (index; index <10; index++) {
      this.print()(index)
    }
  }

///输出结果
I     ---开始执行16:17:47.757
I     ---index:0 16:17:47.759
I     ---index:1 16:17:48.759
I     ---index:2 16:17:49.759
I     ---index:3 16:17:50.760
I     ---index:4 16:17:51.758
I     ---index:5 16:17:52.758
I     ---index:6 16:17:53.758
I     ---index:7 16:17:54.759
I     ---index:8 16:17:55.759
I     ---index:9 16:17:56.758
通过闭包将每次for循环传入闭包函数的index保存下来,不被全局的index改变所影响。这里需要注意,调用print方法需要两个()第一次是获取到return的function,第二个()才是执行这个方法。

点击事件防抖实现

防止在短时间内连续触发点击事件,只需要在每次点击时判断与上次点击时间的时间间隔是否小于阈值,然后做相应的处理即可。因此,我们可以利用闭包,记录每个点击事件的最后点击事件,并且能保证多个点击事件不互相影响,利用了闭包的作用域。
代码实现:

//定义全局放到方法,默认500毫秒,参数类型设为可选参数
export function singleClick(func: Function, interval=500) {
  let lastTime = 0;
  return () => {
    const nowTime = Date.now();
    const remainTime = interval - (nowTime - lastTime);
    if (remainTime <= 0) {
      lastTime = nowTime;
      func();
    }
  };
}
//点击事件调用
Button('防连击按键1').onClick(singleClick(()=>{
  // 点击事件实现。。。
}))
Button('防连击按键1').onClick(singleClick(()=>{
  // 点击事件实现。。。
},1000))

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
标签
1
收藏
回复
举报
回复
    相关推荐