基于JS實(shí)現(xiàn)發(fā)送驗(yàn)證碼的計(jì)時(shí)器效果
一、實(shí)現(xiàn)效果

需求:
- 點(diǎn)擊按鈕后開(kāi)始讀秒
- 讀秒期間不可點(diǎn)擊
- 讀秒結(jié)束后可以繼續(xù)點(diǎn)擊
二、實(shí)現(xiàn)思路(步驟)
1.要做到計(jì)時(shí)器的效果,首先得實(shí)現(xiàn)一個(gè)讀秒的效果
let count = 60; // 這里只做演示說(shuō)明 Gif 中是 10
setInterval(() => {
count = count - 1
}, 1000)
2.清除定時(shí)器的效果,處理狀態(tài)
let count = 10;
let timer = setInterval(() => {
count = count - 1
}, 1000)
// 這里我用 setTimeout 來(lái)做 clearInterval 的操作
setTimeout(function () {
timer && clearInterval(timer)
// 清理定時(shí)器的時(shí)機(jī)為 10 次之后
}, 10 * 1000)
注:
這里對(duì)于 setTimeout 清理 setInterval 這個(gè)定時(shí)器做一個(gè)說(shuō)明
原本我的實(shí)現(xiàn)是在 setInterval 的執(zhí)行中通過(guò)判斷計(jì)數(shù)來(lái)銷毀這個(gè)定時(shí)器的,但是發(fā)現(xiàn)定時(shí)器依然在執(zhí)行,執(zhí)行的原因是:setInterval 函數(shù)會(huì)在執(zhí)行完回調(diào)函數(shù)后,創(chuàng)建一個(gè)新的定時(shí)器,并將舊的定時(shí)器銷毀。 因此,當(dāng)你在 setInterval 中執(zhí)行 clearInterval 時(shí),實(shí)際上是清除了一個(gè)已經(jīng)被銷毀的定時(shí)器。
通過(guò)以上兩步,就可以實(shí)現(xiàn)了需求 1。將上述操作封裝函數(shù)就可以得到一個(gè)簡(jiǎn)單的定時(shí)器功能了。
3.處理定時(shí)器的讀秒期間不可點(diǎn)擊實(shí)現(xiàn)(需求 2)
/**
* @param {number} initCount 調(diào)用次數(shù)
* @param {(count: number) => count} time 定時(shí)器執(zhí)行時(shí)間間隔
* @returns [開(kāi)始調(diào)用, 計(jì)數(shù)器, 是否執(zhí)行中]
*/
let tiggering = false;
export const tigger = (initCount = 60, callback: (count: number) => count) => {
let count = initCount;
let timer: NodeJS.Timeout | null = null
// 如果未觸發(fā),則可以執(zhí)行定時(shí)器
if (!tiggering) {
tiggering = true
timer = setInterval(() => {
count = count - 1
// 定時(shí)器每次執(zhí)行后更新回調(diào),這樣可以在頁(yè)面使用該狀態(tài)
callback(count)
}, time)
}
setTimeout(function () {
// 定時(shí)器結(jié)束時(shí)設(shè)置更新觸發(fā)狀態(tài)
tiggering = false
timer && clearInterval(timer)
}, count * time)
}
在這里我是將邏輯部分抽離為工具函數(shù)的使用,在實(shí)際項(xiàng)目中有步驟 2,在合適的時(shí)機(jī)做相對(duì)應(yīng)的邏輯處理,基本夠用了。
這段代碼的實(shí)現(xiàn)基本沒(méi)什么大的問(wèn)題了,tiggering 狀態(tài)的維護(hù)是放在了工具函數(shù)之外,感覺(jué)不是很優(yōu)雅。在函數(shù)內(nèi)部的實(shí)現(xiàn)話就需要用到閉包維護(hù)內(nèi)部函數(shù)的形式來(lái)保護(hù)這個(gè)變量了,這點(diǎn)大家可以看看表達(dá)下自己的想法~
三、封裝一個(gè)適用的 React 自定義 hook
實(shí)現(xiàn)思路大致和 步驟 3 類似:
import { useState } from 'react'
/**
* @param initCount 調(diào)用次數(shù)
* @param time 定時(shí)器執(zhí)行時(shí)間間隔,這里支持修改真實(shí)的時(shí)間間隔
* @returns [開(kāi)始調(diào)用, 計(jì)數(shù)器, 是否執(zhí)行中]
*/
export default (initCount = 120, time = 1000): [() => void, number, boolean] => {
// 維護(hù)調(diào)用次數(shù)
const [count, setCount] = useState(initCount)
// 維護(hù)觸發(fā)狀態(tài),用于 UI 部分實(shí)現(xiàn)禁用
const [tiggering, setTiggering] = useState(false)
let timer: NodeJS.Timeout | null = null
const tigger = () => {
// 注:在這里又進(jìn)行了一次 setCount 賦值操作,是為了解決第一次驗(yàn)證碼讀秒結(jié)束后,
// 第二次驗(yàn)證碼執(zhí)行(tigger 函數(shù)調(diào)用)時(shí),自定義 hook 已經(jīng)執(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]
}
組件中使用
這里簡(jiǎn)寫(xiě)實(shí)現(xiàn)過(guò)程
// ... 引入略
const [tigger, count, tiggering] = useTimeCount(10)
const sendCode = () => {
// 發(fā)送驗(yàn)證嗎
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>
)
小結(jié)
在實(shí)現(xiàn)這套流程的時(shí)候,一開(kāi)始覺(jué)得是個(gè)簡(jiǎn)單的實(shí)現(xiàn),在實(shí)現(xiàn)過(guò)程中還是踩了一些小坑的,比如上文中說(shuō)到的 clearInterval 的銷毀時(shí)機(jī)的問(wèn)題;以及考慮了下普通函數(shù)封裝(步驟 3)。
到此這篇關(guān)于基于JS實(shí)現(xiàn)發(fā)送驗(yàn)證碼的計(jì)時(shí)器效果的文章就介紹到這了,更多相關(guān)JS計(jì)時(shí)器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- js實(shí)現(xiàn)計(jì)時(shí)器秒表功能
- JS實(shí)現(xiàn)一個(gè)秒表計(jì)時(shí)器
- JavaScript實(shí)現(xiàn)簡(jiǎn)單計(jì)時(shí)器
- JS支付頁(yè)面倒計(jì)時(shí)的實(shí)現(xiàn)示例
- JavaScript實(shí)現(xiàn)簡(jiǎn)單的倒計(jì)時(shí)效果
- javascript實(shí)現(xiàn)倒計(jì)時(shí)小案例
- JS實(shí)現(xiàn)簡(jiǎn)單網(wǎng)頁(yè)倒計(jì)時(shí)器
- 基于JS實(shí)現(xiàn)01支付后的10秒倒計(jì)時(shí)
相關(guān)文章
JavaScript檢查一個(gè)值是否為數(shù)字實(shí)例代碼
眾所周知在JavaScript編程中判斷輸入是否為數(shù)字類型是一個(gè)常見(jiàn)的需求,特別是在處理用戶輸入或者驗(yàn)證表單數(shù)據(jù)時(shí),這篇文章主要介紹了JavaScript檢查一個(gè)值是否為數(shù)字的相關(guān)資料,需要的朋友可以參考下2025-11-11
JavaScript高級(jí)程序設(shè)計(jì)閱讀筆記(六) ECMAScript中的運(yùn)算符(二)
ECMAScript中的運(yùn)算符,學(xué)習(xí)js的朋友可以參考下2012-02-02
JavaScript Uploadify文件上傳實(shí)例
這篇文章主要為大家詳細(xì)介紹了Uploadify文件上傳小實(shí)例,一個(gè)簡(jiǎn)單的jsp上傳小功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02
JavaScript計(jì)算兩個(gè)日期之間天數(shù)的各種方法總結(jié)
這篇文章主要介紹了利用JavaScript計(jì)算兩個(gè)日期之間天數(shù)的各種方法,你可以使用JavaScript的Date對(duì)象來(lái)計(jì)算兩個(gè)字符串日期之間的天數(shù)差異,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-07-07
使用JS正則表達(dá)式 替換括號(hào),尖括號(hào)等
下面小編就為大家?guī)?lái)一篇使用JS正則表達(dá)式 替換括號(hào),尖括號(hào)等。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-11-11
在純TypeScript項(xiàng)目中使用Alias Path問(wèn)題
本文介紹了在大型TypeScript項(xiàng)目中使用別名路徑簡(jiǎn)化模塊導(dǎo)入路徑的方法,主要步驟包括修改tsconfig.json配置別名路徑、確保構(gòu)建工具支持別名路徑,并在項(xiàng)目中使用別名路徑,這有助于提高代碼的可讀性和可維護(hù)性2026-04-04
JavaScript實(shí)現(xiàn)九宮格點(diǎn)擊變色效果
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)九宮格點(diǎn)擊變色效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08
JS實(shí)現(xiàn)跟隨鼠標(biāo)閃爍轉(zhuǎn)動(dòng)色塊的方法
這篇文章主要介紹了JS實(shí)現(xiàn)跟隨鼠標(biāo)閃爍轉(zhuǎn)動(dòng)色塊的方法,涉及javascript操作html元素及css樣式的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-02-02
js canvas實(shí)現(xiàn)簡(jiǎn)單的圖像擴(kuò)散效果
這篇文章主要為大家詳細(xì)介紹了js canvas實(shí)現(xiàn)簡(jiǎn)單的圖像擴(kuò)散效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09

