思否上的许多按钮都没有作重复点击检测的问题,每每致使点击没反应,屡次点击后忽然发表多条相同内容,好比和一位同窗的私信:javascript
又如一个问题下的评论:java
若是你在这篇文章下发表评论,能够不当心多点几下"提交评论
"按钮,会发现也存在相同的问题~~~ios
这个问题怎么解决呢?
简单点,使用一个lock标记,在请求发出时上锁,上锁后就不能够再发请求,能够在请求结束后解锁:axios
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标记。promise
这个方案问题在于,对于每一次按钮点击,咱们都要写个lock标记,至关于重复的逻辑会出如今代码的各个地方——是否是能够封装一下呢?函数
写一个装饰器将逻辑封装起来:post
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来上锁,有两种方法解锁:this
Promise.resolve(promise).finally(done)
。自动解锁使用例子:url
let clickButton = ignoreMultiClick(function (postParams) { if (!checkForm()) return // 假设有一些检测表单的操做,检查不经过则直接返回 // 返回promise return axios.post('urlxxx', postParams).then( // 表单提交成功 ).catch(error => { // 表单提交出错 console.log(error) }) }) button.addEventListener('click', clickButton)
手动解锁:spa
let clickButton = ignoreMultiClick(function (postParams, done) { if (!checkForm()) return done() // 表单验证不经过解锁 axios.post('urlxxx', postParams).then( // 表单提交成功 ).catch(error => { // 表单提交出错 console.log(error) }).finally(() => done()) // 请求结束解锁 }) button.addEventListener('click', clickButton)
普通场景下仍是自动解锁比较简单,由于可能有多个条件分支,手动解锁须要在每个返回的地方都调用done。