記錄--按鈕防連點終極解決方案

来源:https://www.cnblogs.com/smileZAZ/Undeclared/17953017
-Advertisement-
Play Games

這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 引言 在日常前端開發中,我們經常會面對一個讓人頭疼的問題:按鈕被用戶點擊了兩次以上,導致出現重覆提交表單或者發送重覆的請求。這個問題常見而且惱人。為瞭解決這個問題,我們需要一個又簡單又實用的方法,可以在不搞亂原有代碼的情況下,有效地防止按 ...


這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

引言

在日常前端開發中,我們經常會面對一個讓人頭疼的問題:按鈕被用戶點擊了兩次以上,導致出現重覆提交表單或者發送重覆的請求。這個問題常見而且惱人。為瞭解決這個問題,我們需要一個又簡單又實用的方法,可以在不搞亂原有代碼的情況下,有效地防止按鈕被連續點擊。

背景

隨著網頁應用變得越來越複雜,用戶在頁面上的交互也變得越來越頻繁。這就使得按鈕被不小心點擊多次的情況變得非常普遍。一般的解決方法存在一些問題,比如改動原有代碼太多,不夠靈活等。因此,我們需要一種更好的、通用的按鈕防連點方法。

挑戰

在解決按鈕被連點的問題時,我們要面臨一些挑戰。首先,解決方法得適應各種情況,比如表單提交、非同步請求等。其次,我們需要確保解決方法不會讓我們的原有代碼變得混亂,同時還要具備足夠的靈活性。最後,我們希望不修改原有代碼的情況下提供按鈕防連點。

目標

本文的目標是為大家提供一個簡單易用的按鈕防連點解決方案。我們會深入講解方案的設計原理和實現細節,並且會附上完整的源碼解析。通過學習本文,你將能夠理解這個解決方案的原理,同時學會如何在實際項目中應用這個方法。希望通過這篇文章,按鈕防連點問題不再讓你感到頭疼,反而變得得心應手。

防連點原理概述

在開始實現我們的按鈕防連點終極解決方案之前,讓我們首先理解一下連點問題的本質以及為什麼傳統的解決方案可能存在一些問題。

連點問題的本質

按鈕連點問題的核心在於,用戶在短時間內多次點擊按鈕,導致觸發相同的操作。這可能引發一系列不良後果,比如重覆提交表單、重覆發送請求等。為瞭解決這個問題,我們需要一種機制來在用戶點擊按鈕後一段時間內禁用按鈕,防止其再次觸發相同的操作。

常規解決方案的局限性

傳統的解決方案往往通過在點擊按鈕後添加禁用狀態,然後在一段時間後再啟用按鈕,來防止連點問題。然而,這種方法存在一些局限性。首先,它可能需要修改原有的按鈕組件,使得在多個地方應用時不夠靈活。其次,由於採用了定時器等機制,可能導致在某些情況下並不准確,或者在非同步操作中存在問題。

給按鈕加指令

創建一個可復用的Vue自定義指令,該指令能夠動態地管理按鈕的狀態,以防止用戶在短時間內多次點擊按鈕。關鍵之處在於,我們還將支持外部傳遞參數,以自定義按鈕的禁用時間。

創建可復用的防連點按鈕組件

首先,我們需要創建一個按鈕組件,該組件可以接受我們的自定義指令。這樣,我們就可以在需要的按鈕上應用這個指令。

<template>
  <button v-prevent-duplicate-clicks="2000" @click="handleClick">防連點按鈕</button>
</template>

<script>
import preventDuplicateClicks from '@/path-to-your-file/preventDuplicateClicks';

export default {
  directives: {
    preventDuplicateClicks,
  },
  methods: {
    handleClick() {
      // 處理按鈕點擊事件的業務邏輯
    },
  },
};
</script>

在上述代碼中,我們創建了一個按鈕組件,通過 v-prevent-duplicate-clicks 指令來防止按鈕的連點行為。並且,我們通過傳遞參數 "2000" 指定了按鈕禁用的時間為2秒。

指令文件

現在,創建一個名為 preventDuplicateClicks.js 的文件,該文件包含我們的自定義指令。

// preventDuplicateClicks.js

const preventDuplicateClicks = {
  mounted(el, binding) {
    const { value } = binding;

    el.addEventListener('click', () => {
      if (!el.disabled) {
        el.disabled = true;
        setTimeout(() => {
          el.disabled = false;
        }, value || 1000); // 預設1秒後恢復按鈕點擊
      }
    });
  },
};

export default preventDuplicateClicks;

在上述代碼中,我們定義了一個名為 preventDuplicateClicks 的自定義指令,它在按鈕被點擊時阻止多次點擊。通過 setTimeout 來實現按鈕在一定時間後恢復點擊。此外,我們在指令上支持了外部參數的傳遞,用於自定義按鈕的禁用時間。

以為估計是80%的前端的解決方案,我在面試中也問過類似的問題,很多人能給出指令的寫法已經很好了。有如下問題:

  • 侵入已有代碼:如果是老的項目,都要添加這個功能,要去批量改,很麻煩;
  • 禁用時間錯誤:我們假設給的參數是2秒,一個介面請求超過2秒, 用戶在請求響應之前依然會重覆發起請求。如果介面幾十毫秒就返回(是異常,讓重試),用戶也得等2秒;

那麼有沒有更好的解決方案了,肯定是有的,我們來分析以上兩個問題:

  • 侵入代碼:我們通過重寫已有組件可以做到,假設用的el-button,我們在全局把el-button覆蓋成我們自己的即可
  • 禁用時間錯誤:既然設置是錯的,那我們就不設置,按鈕肯定都有一個onClick的函數,我們只要在onClick執行之前設置禁用,執行後啟用即可。

終極解決方案

有了以上的分析,我們直接貼代碼吧,我司用的vue + ant design vue,其他組件庫,類似寫法吧。

<script>
import { Button as AntButton } from 'ant-design-vue'

export default {
  name: 'AButton',
  props: {
    ...AntButton.props,
    delay: {
      type: Number,
      default: 300
    }
  },
  data() {
    return {
      customLoading: false,
      ownDisabled: false
    }
  },
  computed: {
    allProps() {
      return Object.assign({}, this.$props, {
        loading: this.customLoading || this.loading,
        type: this.$props.type || 'primary'
      })
    }
  },
  methods: {
    async handler (...arg) {
      if (this.ownDisabled) return
      this.customLoading = true
      this.ownDisabled = true
      const { click: preClick } = this.$listeners || {}
      const ret = preClick(...arg)
      try {
        await Promise.resolve(ret)
      } finally {
        this.customLoading = false
        let timer = setTimeout(() => {
          this.ownDisabled = false
          clearTimeout(timer)
          timer = null
        }, this.delay)
      }
    }
  },
  render() {
    return (
      <AntButton props={this.allProps} onClick={this.handler}>
        {this.$slots?.default}
      </AntButton>
    )
  }
}
</script>
需要註意的是,使用的時候 onClick 需要返回promise,這算一個很容易遵守的約定吧。另外加個預設延遲300ms,目的我記得好像是為了避免路由跳轉時的問題,大家可以自己調整。

本文轉載於:

https://juejin.cn/post/7304946949941608475

如果對您有所幫助,歡迎您點個關註,我會定時更新技術文檔,大家一起討論學習,一起進步。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 複習-面試題 多個線程同時去查詢資料庫的這條數據,那麼我們可以在第一個查詢數據的請求上使用一個 互斥鎖來鎖住它。 其他的線程走到這一步拿不到鎖就等著,等第一個線程查詢到了數據,然後做緩存。 後面的線程進來發現已經有緩存了,就直接走緩存。 canal canal [kə'næl],中文翻譯為 水道/管 ...
  • 最近在分析ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)這個報錯的常見原因。 在分析的過程中,不可避免會涉及到 MySQL 身份驗證的一些實現細節。 加之之前對這一塊就有很多疑問, ...
  • DolphinDB 是一款高性能時序資料庫。DolphinDB 集成了功能強大的編程語言和高容量高速度的批流一體數據分析系統,為海量數據(特別是時間序列數據)的快速存儲、檢索、計算及分析提供一站式解決方案。在實際生產環境中,經常存在數據導入、轉換、查詢計算,更新等一系列流程任務,各個部分之間存在依賴 ...
  • 透明數據加密(Transparent Data Encryption,簡稱TDE),作為一種在數據“靜止”時保護數據的機制,對數據文件執行實時I/O加密和解密 ...
  • ​ 當項目的SQL查詢慢得像蝸牛爬行時,用戶的耐心也在一點點被消耗,作為研發,我們可不想看到這樣的事。這篇文章將結合行雲部署項目的實踐經驗,帶你走進SQL優化的奇妙世界,一起探索如何讓那些龜速的查詢飛起來! 序章:EXPLAIN - 揭開查詢的神秘面紗 EXPLAIN命令是資料庫管理員和SQL開發人 ...
  • 一、準備一個Docker的sqlserver #創建掛載數據文件夾 mkdir -p /home/mssql/data #創建掛載日誌文件夾 mkdir /home/mssql/log #給文件夾許可權 chmod 777 /home/mssql/data chmod 777 /home/mssql/ ...
  • 原文地址: Android 藍牙使用 - Stars-One的雜貨小窩 公司項目需求需要實現監聽藍牙耳機連接,且要獲取藍牙耳機電量功能,翻了不少官方文檔,記錄下技術調研代碼 註:本文沒有研究藍牙配對功能 關於藍牙許可權適配 Android12以後,申請藍牙許可權需要申請一組,如新增的幾個許可權,需要一起申 ...
  • 在上傳一篇文獻閱讀筆記到Github page時發現公式無法正常顯示,之前在typora中能夠正常顯示的代碼在網頁上顯示為純latex格式於是進行了一些搜索。 我使用的Jekyll模板是chirpy,具體效果可能與使用的模板也有關係。 問題原因 這個問題的原因出在GitHub Page里的Jekyl ...
一周排行
    -Advertisement-
    Play Games
  • 前言 插件化的需求主要源於對軟體架構靈活性的追求,特別是在開發大型、複雜或需要不斷更新的軟體系統時,插件化可以提高軟體系統的可擴展性、可定製性、隔離性、安全性、可維護性、模塊化、易於升級和更新以及支持第三方開發等方面的能力,從而滿足不斷變化的業務需求和技術挑戰。 一、插件化探索 在WPF中我們想要開 ...
  • 歡迎ReaLTaiizor是一個用戶友好的、以設計為中心的.NET WinForms項目控制項庫,包含廣泛的組件。您可以使用不同的主題選項對項目進行個性化設置,並自定義用戶控制項,以使您的應用程式更加專業。 項目地址:https://github.com/Taiizor/ReaLTaiizor 步驟1: ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • Channel 是乾什麼的 The System.Threading.Channels namespace provides a set of synchronization data structures for passing data between producers and consume ...
  • efcore如何優雅的實現按年分庫按月分表 介紹 本文ShardinfCore版本 本期主角: ShardingCore 一款ef-core下高性能、輕量級針對分表分庫讀寫分離的解決方案,具有零依賴、零學習成本、零業務代碼入侵適配 距離上次發文.net相關的已經有很久了,期間一直在從事java相關的 ...
  • 前言 Spacesniffer 是一個免費的文件掃描工具,通過使用樹狀圖可視化佈局,可以立即瞭解大文件夾的位置,幫助用戶處理找到這些文件夾 當前系統C盤空間 清理後系統C盤空間 下載 Spacesniffer 下載地址:https://spacesniffer.en.softonic.com/dow ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • 一、ReZero簡介 ReZero是一款.NET中間件 : 全網唯一開源界面操作就能生成API , 可以集成到任何.NET6+ API項目,無破壞性,也可讓非.NET用戶使用exe文件 免費開源:MIT最寬鬆協議 , 一直從事開源事業十年,一直堅持開源 1.1 純ReZero開發 適合.Net Co ...
  • 一:背景 1. 講故事 停了一個月沒有更新文章了,主要是忙於寫 C#內功修煉系列的PPT,現在基本上接近尾聲,可以回頭繼續更新這段時間分析dump的一些事故報告,有朋友微信上找到我,說他們的系統出現了大量的http超時,程式不響應處理了,讓我幫忙看下怎麼回事,dump也抓到了。 二:WinDbg分析 ...
  • 開始做項目管理了(本人3年java,來到這邊之後真沒想到...),天天開會溝通整理需求,他們講話的時候忙裡偷閑整理一下常用的方法,其實語言還是有共通性的,基本上看到方法名就大概能猜出來用法。出去打水的時候看到外面太陽好好,真想在外面坐著曬太陽,回來的時候好兄弟三年前送給我的鍵盤D鍵不靈了,在打"等待 ...