1. 程式人生 > 其它 >優雅解決按鈕”重複點選“問題

優雅解決按鈕”重複點選“問題

一、這個問題怎麼解決呢?

簡單點,使用一個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)。

https://www.houdianzi.com/xalogo/ 西安logo設計

三、使用例項

自動解鎖使用例子:

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()) // 請求結束解鎖
})
button.addEventListener('click', clickButton)

普通場景下還是自動解鎖比較簡單,因為可能有多個條件分支,手動解鎖需要在每一個返回的地方都呼叫done。