php重复点击按钮无效,优雅解决按钮”重复点击“问题

一、对思否的一点吐槽

思否上的许多按钮都没有做重复点击检测的问题,往往导致点击没反应,多次点击后突然发表多条相同内容,比如和一位同学的私信:

bVcKPAB

又如一个问题下的评论:

bVcKPt0

如果你在这篇文章下发表评论,可以不小心多点几下"提交评论"按钮,会发现也存在相同的问题——如果你的手速比网速快的话。

这个问题怎么解决呢?

简单点,使用一个lock标记,在请求发出时上锁,上锁后就不可以再发请求,可以在请求结束后解锁:let clickButton = (function () {

let lock = false

return function (postParams) {

if (lock) return

lock = true

// 假设使用axios发送请求

axios.post('urlxxx', postParams).then(

// 表单提交成功

).catch(error => {

// 表单提交出错

console.log(error)

}).finally(() => {

// 不管成功失败 都解锁

lock = false

})

}

})()

button.addEventListener('click', clickButton)

当然对于button按钮,可以使用setAttribute('disabled', xxx)和removeAttribute('disabled')来代替lock标记。

这个方案问题在于,对于每一次按钮点击,我们都要写个lock标记,相当于重复的逻辑会出现在代码的各个地方——是不是可以封装一下呢?

二、封装按钮锁定、解锁逻辑

写一个装饰器将逻辑封装起来:function ignoreMultiClick(func, manual = false) {

let lock = false

return function (...args) {

if (lock) return

lock = true

let done = () => (lock = false)

if (manual) return func.call(this, ...args, done)

let promise = func.call(this, ...args)

Promise.resolve(promise).finally(done)

return promise

}

}

将想监听点击回调函数func作为传递给ignoreMultiClick进行装饰,会返回一个新的函数,使用该函数作为点击的回调事件即可。

这里同样用了一个标记lock来上锁,有两种方法解锁:手动解锁:可以给ignoreMultiClick传递一个参数manual,意思是主动调用解锁。若该参数为truthy,则点击事件触发时会给原始的点击回调func传递一个参数done,done是一个函数,调用它可以解锁。

自动解锁:可以使原监听函数func返回一个promise,在该promise决议后自动执行解锁操作。因为Promise管理回调函数非常方便,并且像axios这样非常常用的请求库返回值本身也是一个promise,所以默认情况使用这种方式。当然返回promise并不是必须的,有时候我们在发请求前会进行一些验证,验证没通过则直接return,此时装饰器函数也能正常处理,因为使用Promise.resolve包裹了一下promise: Promise.resolve(promise).finally(done)。

三、使用实例

自动解锁使用例子:let clickButton = ignoreMultiClick(function (postParams) {

if (!checkForm()) return // 假设有一些检测表单的操作,检查不通过则直接返回

// 返回promise

return axios.post('urlxxx', postParams).then(

// 表单提交成功

).catch(error => {

// 表单提交出错

console.log(error)

})

})

button.addEventListener('click', clickButton)

手动解锁:let clickButton = ignoreMultiClick(function (postParams, done) {

if (!checkForm()) return done() // 表单验证不通过解锁

axios.post('urlxxx', postParams).then(

// 表单提交成功

).catch(error => {

// 表单提交出错

console.log(error)

}).finally(() => done()) // 请求结束解锁

}, true)

button.addEventListener('click', clickButton)

普通场景下还是自动解锁比较简单,因为可能有多个条件分支,手动解锁需要在每一个返回的地方都调用done。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值