基于JS實現發(fā)送驗證碼的計時器效果
一、實現效果
需求:
- 點擊按鈕后開始讀秒
- 讀秒期間不可點擊
- 讀秒結束后可以繼續(xù)點擊
二、實現思路(步驟)
1.要做到計時器的效果,首先得實現一個讀秒的效果
let count = 60; // 這里只做演示說明 Gif 中是 10 setInterval(() => { count = count - 1 }, 1000)
2.清除定時器的效果,處理狀態(tài)
let count = 10; let timer = setInterval(() => { count = count - 1 }, 1000) // 這里我用 setTimeout 來做 clearInterval 的操作 setTimeout(function () { timer && clearInterval(timer) // 清理定時器的時機為 10 次之后 }, 10 * 1000)
注:
這里對于 setTimeout
清理 setInterval
這個定時器做一個說明
原本我的實現是在 setInterval
的執(zhí)行中通過判斷計數來銷毀這個定時器的,但是發(fā)現定時器依然在執(zhí)行,執(zhí)行的原因是:setInterval
函數會在執(zhí)行完回調函數后,創(chuàng)建一個新的定時器,并將舊的定時器銷毀。 因此,當你在 setInterval
中執(zhí)行 clearInterval
時,實際上是清除了一個已經被銷毀的定時器。
通過以上兩步,就可以實現了需求 1。將上述操作封裝函數就可以得到一個簡單的定時器功能了。
3.處理定時器的讀秒期間不可點擊實現(需求 2)
/** * @param {number} initCount 調用次數 * @param {(count: number) => count} time 定時器執(zhí)行時間間隔 * @returns [開始調用, 計數器, 是否執(zhí)行中] */ let tiggering = false; export const tigger = (initCount = 60, callback: (count: number) => count) => { let count = initCount; let timer: NodeJS.Timeout | null = null // 如果未觸發(fā),則可以執(zhí)行定時器 if (!tiggering) { tiggering = true timer = setInterval(() => { count = count - 1 // 定時器每次執(zhí)行后更新回調,這樣可以在頁面使用該狀態(tài) callback(count) }, time) } setTimeout(function () { // 定時器結束時設置更新觸發(fā)狀態(tài) tiggering = false timer && clearInterval(timer) }, count * time) }
在這里我是將邏輯部分抽離為工具函數的使用,在實際項目中有步驟 2,在合適的時機做相對應的邏輯處理,基本夠用了。
這段代碼的實現基本沒什么大的問題了,tiggering 狀態(tài)的維護是放在了工具函數之外,感覺不是很優(yōu)雅。在函數內部的實現話就需要用到閉包維護內部函數的形式來保護這個變量了,這點大家可以看看表達下自己的想法~
三、封裝一個適用的 React 自定義 hook
實現思路大致和 步驟 3 類似:
import { useState } from 'react' /** * @param initCount 調用次數 * @param time 定時器執(zhí)行時間間隔,這里支持修改真實的時間間隔 * @returns [開始調用, 計數器, 是否執(zhí)行中] */ export default (initCount = 120, time = 1000): [() => void, number, boolean] => { // 維護調用次數 const [count, setCount] = useState(initCount) // 維護觸發(fā)狀態(tài),用于 UI 部分實現禁用 const [tiggering, setTiggering] = useState(false) let timer: NodeJS.Timeout | null = null const tigger = () => { // 注:在這里又進行了一次 setCount 賦值操作,是為了解決第一次驗證碼讀秒結束后, // 第二次驗證碼執(zhí)行(tigger 函數調用)時,自定義 hook 已經執(zhí)行,count 的值為 0 的情況 setCount(initCount) if (!tiggering) { setTiggering(true) timer = setInterval(() => { setCount(count => count - 1) }, time) } setTimeout(function () { timer && clearInterval(timer) setTiggering(false) }, initCount * time) } return [tigger, count, tiggering] }
組件中使用
這里簡寫實現過程
// ... 引入略 const [tigger, count, tiggering] = useTimeCount(10) const sendCode = () => { // 發(fā)送驗證嗎 getMailCode({ receiver: code }).then(res => { if (res) { tigger() // 這里可以執(zhí)行其他邏輯,如發(fā)送成功的提示 } }) } return ( <Button disabled={tiggering} className='send-btn' onClick={sendCode}> {tiggering ? `${count}s` : 'Send code'} </Button> )
小結
在實現這套流程的時候,一開始覺得是個簡單的實現,在實現過程中還是踩了一些小坑的,比如上文中說到的 clearInterval
的銷毀時機的問題;以及考慮了下普通函數封裝(步驟 3)。
到此這篇關于基于JS實現發(fā)送驗證碼的計時器效果的文章就介紹到這了,更多相關JS計時器內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!