思否上的許多按鈕都沒有作重複點擊檢測的問題,每每致使點擊沒反應,屢次點擊後忽然發表多條相同內容,好比和一位同窗的私信:
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。