当前位置: 首页 > news >正文

HarmonyOS ClickUtil 节流与防抖:彻底搞懂按钮防重复点击

目录

    • 概述
    • 一、为什么需要节流和防抖?
    • 二、节流 vs 防抖,傻傻分不清?
    • 三、ClickUtil 源码解析
      • 3.1 核心状态
      • 3.2 throttle — 节流实现
      • 3.3 debounce — 防抖实现
    • 四、完整 Demo 演示
      • 4.1 节流 Demo
      • 4.2 防抖 Demo
      • 4.3 节流 UI
      • 4.4 防抖 UI
    • 五、运行效果对比
    • 六、如何选择节流还是防抖?
    • 七、API 速查表
    • 八、小结

概述

近期发现一款很有意思的HarmonyOS 三方库, 地址 @pura/harmony-utils(V1.4.0) , 作者是"桃花镇童长老", 我这里也是直接通过该作者公布的源码进行案例编写进行,写了到目前写了一部分demo ,感觉确实很有帮助,这里呢也是开始写一个系列的演示demo 供大家参考。如有帮助可以在OpenHarmony中进行下载安装进行使用哦

案例demo导航展示

↓↓↓↓↓↓接下来言归正传 ↓↓↓↓

一、为什么需要节流和防抖?

在移动应用中,用户往往会在极短时间内连续点击按钮。如果没有任何防护措施:

  • 重复提交表单:用户点了"提交"后因网络慢又点了几次,服务器收到多个相同请求
  • 重复触发导航:点击跳转按钮连续触发,路由栈里压了多个相同页面
  • 接口被刷:搜索框每次击键都请求接口,每秒钟可能发起几十个请求

节流(Throttle)防抖(Debounce)是解决这类问题的经典方案。

二、节流 vs 防抖,傻傻分不清?

用一个形象的比喻来区分:

节流:就像地铁的闸机,在规定时间内只让一个人通过,后面的人必须等前一个人完全通过后才能进入。适合"限制频率"的场景。

防抖:就像电梯门,只要还有人进来,电梯门就一直等待。直到没有人进来(停止操作),等待一段时间后才关门执行。适合"等待停止"的场景。

节流(Throttle)防抖(Debounce)
核心逻辑固定时间内只执行一次最后一次操作后延迟执行
触发时机立即执行或延迟执行停止操作后执行
适合场景防重复提交、滚动事件搜索输入、窗口缩放

三、ClickUtil 源码解析

3.1 核心状态

exportclassClickUtil{privatestaticthrottleTimeoutID:number;//节流timeoutIDprivatestaticflag:boolean=false;//节流flag,true=已经进入执行状态了privatestaticdefaultId:string=DateUtil.getTodayTime().toString();//防抖Id
  • throttleTimeoutID:存储节流定时器的 ID,用于在等待期结束后重置flag
  • flag:节流的门控标志,true表示正在节流冷却期
  • defaultId:防抖的默认 ID(用时间戳初始化),当只有一个防抖事件时使用

3.2 throttle — 节流实现

staticthrottle(func:()=>void,wait:number=1000,immediate:boolean=true){if(immediate){if(!ClickUtil.flag){ClickUtil.flag=true;typeoffunc==='function'&&func();ClickUtil.throttleTimeoutID=setTimeout(()=>{ClickUtil.flag=false;clearTimeout(ClickUtil.throttleTimeoutID);},wait);}}else{if(!ClickUtil.flag){ClickUtil.flag=true;ClickUtil.throttleTimeoutID=setTimeout(()=>{ClickUtil.flag=false;typeoffunc==='function'&&func();clearTimeout(ClickUtil.throttleTimeoutID);},wait);}}}

参数说明:

参数类型默认值说明
func() => void必填要执行的回调函数
waitnumber1000节流冷却时间(毫秒)
immediatebooleantruetrue=立即执行后冷却,false=冷却结束后执行

两种模式的时序对比:

immediate = true(立即模式):

点击 → 立即执行 → 冷却 1000ms → 可以再次点击

immediate = false(延迟模式):

点击 → 冷却 1000ms → 执行 → 可以再次点击

3.3 debounce — 防抖实现

staticdebounce(func:()=>void,wait:number=1000,clickId:string=ClickUtil.defaultId){letcacheID=CacheUtil.get<number>(`ClickUtil_debounce_timeoutID_${clickId}`);//获取idif(cacheID!==undefined&&cacheID!==null){clearTimeout(cacheID);}lettimeoutID=setTimeout(()=>{typeoffunc==='function'&&func();clearTimeout(timeoutID);},wait);CacheUtil.put<number>(`ClickUtil_debounce_timeoutID_${clickId}`,timeoutID);//缓存id}

参数说明:

参数类型默认值说明
func() => void必填要执行的回调函数
waitnumber1000防抖等待时间(毫秒)
clickIdstringdefaultId事件标识,用于区分多个独立的防抖事件

防抖的工作原理:

  1. 每次触发时,先从CacheUtil中取出上一次的timeoutID
  2. 如果存在,调用clearTimeout取消上一次的定时器
  3. 重新设置一个新的定时器
  4. 将新的timeoutID存入CacheUtil

这样,只要在wait毫秒内持续点击,定时器一直被重置;只有停止点击并等待wait毫秒后,函数才会执行。

多事件 ID 的设计:

通过clickId参数,可以维护多个独立的防抖事件:

// 搜索框防抖ClickUtil.debounce(()=>this.doSearch(),500,'search_input');// 评论提交防抖ClickUtil.debounce(()=>this.submitComment(),1000,'comment_submit');

两个事件在CacheUtil中的 key 分别是:

  • ClickUtil_debounce_timeoutID_search_input
  • ClickUtil_debounce_timeoutID_comment_submit

互不干扰。

四、完整 Demo 演示

来自CacheCharClickDemoPage.ets的 ClickUtil 演示部分:

4.1 节流 Demo

@StatethrottleCount:number=0;@StatethrottleImmediate:boolean=true;doThrottle(){ClickUtil.throttle(()=>{this.throttleCount++;this.addLog('Throttle',`触发!累计:${this.throttleCount}`,'success');},1500,this.throttleImmediate);}

4.2 防抖 Demo

@StatedebounceCount:number=0;@StatedebounceDelay:number=1000;doDebounce(){ClickUtil.debounce(()=>{this.debounceCount++;this.addLog('Debounce',`执行!累计:${this.debounceCount}`,'success');},this.debounceDelay,'demo_debounce');}

4.3 节流 UI

// 模式选择Row(){Text('触发模式:').fontSize(12).fontColor('#888')Radio({value:'imm',group:'throttleMode'}).checked(this.throttleImmediate).onChange((v:boolean)=>{if(v)this.throttleImmediate=true;})Text('立即执行').fontSize(12).margin({left:2}).onClick(()=>{this.throttleImmediate=true;})Radio({value:'delayed',group:'throttleMode'}).checked(!this.throttleImmediate).onChange((v:boolean)=>{if(v)this.throttleImmediate=false;})Text('延迟执行').fontSize(12).margin({left:2}).onClick(()=>{this.throttleImmediate=false;})}.margin({bottom:10})// 触发按钮Button('快速连续点击我(节流)').width('100%').height(48).borderRadius(10).backgroundColor('#4080FF').fontColor('#FFF').fontSize(14).onClick(()=>{this.doThrottle();})

4.4 防抖 UI

// 延迟时间调节Row(){Text('延迟时间:').fontSize(12).fontColor('#888')Slider({value:this.debounceDelay,min:300,max:3000,step:100,style:SliderStyle.OutSet}).layoutWeight(1).showTips(true).onChange((v:number)=>{this.debounceDelay=v;})Text(`${this.debounceDelay}ms`).fontSize(12).fontColor('#4080FF').margin({left:8})}.margin({bottom:10})// 触发按钮Button('快速连续点击我(防抖)').width('100%').height(48).borderRadius(10).backgroundColor('#FF9800').fontColor('#FFF').fontSize(14).onClick(()=>{this.doDebounce();})

五、运行效果对比

节流测试(immediate=true,间隔 1500ms):

在 1.5 秒内快速点击 10 次,日志只会出现 1 条:

[Throttle] 触发!累计: 1 次

等 1.5 秒后再次点击,才会新增一条日志。

防抖测试(延迟 1000ms):

快速点击 10 次,不会立即有日志。停止点击,等 1 秒后才出现 1 条:

[Debounce] 执行!累计: 1 次

六、如何选择节流还是防抖?

场景推荐方案原因
提交按钮防重复节流(immediate=true第一次点击立即响应,后续冷却
搜索框实时搜索防抖等用户停止输入后才请求
页面滚动事件节流固定频率触发,不能太密集
窗口 resize防抖等缩放停止后再更新布局
点赞/收藏按钮节流(immediate=true第一次立即反馈,避免重复
验证码发送节流(较长wait60 秒内只能发送一次

七、API 速查表

方法参数说明
throttle(fn, wait, immediate)fn: 回调;wait: 间隔毫秒(默认1000);immediate: 是否立即执行(默认true)节流,固定时间窗口内只执行一次
debounce(fn, wait, clickId)fn: 回调;wait: 等待毫秒(默认1000);clickId: 事件ID防抖,停止触发后延迟执行

八、小结

ClickUtil将两种经典的交互优化方案封装为简洁的静态方法:

  • throttle:适合需要"限制频率"的场景,immediate参数控制是先执行还是后执行
  • debounce:适合需要"等待停止"的场景,clickId参数支持多个独立防抖事件

底层依赖CacheUtil存储防抖定时器 ID,这也体现了工具类之间协作的设计思想。在任何需要防止重复操作的场景,ClickUtil都是首选方案。

http://www.jsqmd.com/news/888784/

相关文章:

  • 从文本到PDF:极简文档转换工具的技术实现与设计哲学
  • 2026年亲测有效:3种高效降论文AIGC率的方法 - 降AI实验室
  • JMeter高并发压测脚本设计范式:可伸缩、可观测、可诊断
  • 如何快速定位手机号码地理位置:终极开源工具使用指南
  • 从零到一:手把手教你用Playwright+Pytest+Yaml+Allure搭建一个能跑起来的UI自动化框架(保姆级避坑指南)
  • 从零实现五子棋AI:极小化极大算法与Alpha-Beta剪枝实战
  • 2026 年福建莆田全屋高端定制家居设计与选材选型指南
  • 3步解锁百度网盘真实下载速度:告别龟速下载的技术秘籍
  • Java集合全解析:体系架构+分类详解+底层原理+使用场景
  • 01-认知篇-总览-HybridCLR是什么
  • 基于大语言模型的GitHub PR描述自动生成工具设计与实践
  • 微信聊天记录误删别慌!官方恢复方法实操指南
  • 安全攻防 - 03 TLCP 握手:双证书、密码套件与常见术语
  • 用Xilinx Artix-7 FPGA驱动TDC-GPX2:一个完整的状态机SPI控制模块实现
  • 学生党免费降AI工具实测:靠谱降重降AI首选推荐
  • 2026年昭通市本地上门黄金回收门店指南 彩金+铂金+金条+白银回收门店联系方式推荐 - 大熊猫898989
  • 三步实现百度网盘高速下载:告别龟速,拥抱全速时代
  • 百度网盘提取码一键查询:3步告别资源获取烦恼
  • 别再盲选大模型了!DeepSeek-V2/V3/R1在中文长文本、代码生成、数学推理三类场景的TOP-1准确率差距高达23.6%,你用对版本了吗?
  • bili2text终极指南:三分钟将B站视频变文字稿的免费神器
  • BepInEx插件框架:让每个玩家都能成为游戏改造师
  • 2026年岳阳市正规上门黄金白银回收品牌门店名录 K金+铂金+金条+银条回收门店联系方式推荐+指南 - 盛世金银回收
  • 2026年肇庆市本地上门黄金回收门店指南 彩金+铂金+金条+白银回收门店联系方式推荐 - 大熊猫898989
  • IDA Pro花指令清除三法:字节匹配、CFG裁剪与语义替换
  • 2026 SSH工具怎么选:多台 VPS 管理时,什么类型更省心?
  • 智能体+RAG+规划:构建AI节日助手的架构设计与工程实践
  • 三维针刺材料多尺度力学仿真复现
  • 深圳电力设备插箱厂家
  • 用AT89C51单片机+Proteus仿真,手把手教你做一个能测方波、锯齿波的简易数字频率计
  • 2026年镇江市本地上门黄金回收门店指南 彩金+铂金+金条+白银回收门店联系方式推荐 - 大熊猫898989