QQ登录

只需要一步,快速开始

APP扫码登录

只需要一步,快速开始

手机号码,快捷登录

手机号码,快捷登录

查看: 2405|回复: 0

[HTML/CSS/JS] 如何优雅的解决按钮“重复点击”问题

[复制链接]

等级头衔

积分成就    金币 : 2841
   泡泡 : 1516
   精华 : 6
   在线时间 : 1294 小时
   最后登录 : 2024-11-21

丰功伟绩

优秀达人突出贡献荣誉管理论坛元老

联系方式
发表于 2021-1-1 10:01:35 | 显示全部楼层 |阅读模式
一、问题怎么解决; }  V6 c8 {; g1 ^
       简单点,使用一个lock标记,在请求发出时上锁,上锁后就不可以再发请求,可以在请求结束后解锁:
1 j6 A, s2 M" g4 O
  1. let clickButton = (function () {
  2.   let lock = false
  3.   return function (postParams) {
  4.     if (lock) return
  5.     lock = true
  6.     // 假设使用axios发送请求
  7.     axios.post('urlxxx', postParams).then(
  8.       // 表单提交成功
  9.     ).catch(error => {
  10.       // 表单提交出错
  11.       console.log(error)
  12.     }).finally(() => {
  13.       // 不管成功失败 都解锁
  14.       lock = false
  15.     })
  16.   }
  17. })()
  18. button.addEventListener('click', clickButton)
      当然对于button按钮,可以使用setAttribute('disabled', xxx)和removeAttribute('disabled')来代替lock标记。这个方案问题在于,对于每一次按钮点击,我们都要写个lock标记,相当于重复的逻辑会出现在代码的各个地方——是不是可以封装一下呢?
& V; W1 C$ ^+ n" Z二、封装按钮锁定、解锁逻辑% M  y* l  f' H. |6 d
       写一个装饰器将逻辑封装起来:
6 O, i1 \6 I" c9 w! E9 ?
  1. function ignoreMultiClick(func, manual = false) {
  2.   let lock = false
  3.   return function (...args) {
  4.     if (lock) return
  5.     lock = true
  6.     let done = () => (lock = false)
  7.     if (manual) return func.call(this, ...args, done)
  8.     let promise = func.call(this, ...args)
  9.     Promise.resolve(promise).finally(done)
  10.     return promise
  11.   }
  12. }
      将想监听点击回调函数func作为传递给ignoreMultiClick进行装饰,会返回一个新的函数,使用该函数作为点击的回调事件即可。
9 k+ j; _* T% [2 S4 E2 J. V       这里同样用了一个标记lock来上锁,有两种方法解锁:, H8 O4 i! I5 M* Z1 u( j, v
手动解锁:可以给ignoreMultiClick传递一个参数manual,意思是主动调用解锁。若该参数为truthy,则点击事件触发时会给原始的点击回调func传递一个参数done,done是一个函数,调用它可以解锁。& K1 T) y+ Z  {
自动解锁:可以使原监听函数func返回一个promise,在该promise决议后自动执行解锁操作。因为Promise管理回调函数非常方便,并且像axios这样非常常用的请求库返回值本身也是一个promise,所以默认情况使用这种方式。
9 W$ B: ^# J( n+ d       当然返回promise并不是必须的,有时候我们在发请求前会进行一些验证,验证没通过则直接return,此时装饰器函数也能正常处理,因为使用Promise.resolve包裹了一下promise:Promise.resolve(promise).finally(done)。* v& P  \0 ]( K: }2 f! J" C1 `( f
三、使用实例2 M, n+ D6 P# B3 p4 Q
       自动解锁使用例子:# l5 s1 v& V6 Z8 X8 Y- s
  1. let clickButton = ignoreMultiClick(function (postParams) {
  2.   if (!checkForm()) return // 假设有一些检测表单的操作,检查不通过则直接返回
  3.   // 返回promise
  4.   return axios.post('urlxxx', postParams).then(
  5.     // 表单提交成功
  6.   ).catch(error => {
  7.     // 表单提交出错
  8.     console.log(error)
  9.   })
  10. })
  11. button.addEventListener('click', clickButton)
      手动解锁使用例子:* n% K+ N$ P: P
  1. let clickButton = ignoreMultiClick(function (postParams, done) {
  2.   if (!checkForm()) return done() // 表单验证不通过解锁
  3.   axios.post('urlxxx', postParams).then(
  4.     // 表单提交成功
  5.   ).catch(error => {
  6.     // 表单提交出错
  7.     console.log(error)
  8.   }).finally(() => done()) // 请求结束解锁
  9. })
  10. button.addEventListener('click', clickButton)
      普通场景下还是自动解锁比较简单,因为可能有多个条件分支,手动解锁需要在每一个返回的地方都调用done。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|paopaomj.COM ( 渝ICP备18007172号|渝公网安备50010502503914号 )

GMT+8, 2024-11-22 02:36

Powered by paopaomj X3.5 © 2016-2025 sitemap

快速回复 返回顶部 返回列表