jia-countdown-verify 驗證碼倒計時按鈕組件
一個用于發送短信驗證碼的倒計時按鈕組件,支持自定義樣式、倒計時時間和文本內容。適用于各種需要驗證碼功能的表單場景。
代碼已經 發布到插件市場 可以自行下載 下載地址
特性
- 支持自定義按鈕樣式(顏色、大小、圓角等)
- 支持自定義倒計時時間
- 支持自定義按鈕文本
- 支持手動觸發和自動開始倒計時
- 支持重置倒計時狀態
- 提供多種事件回調(發送、倒計時變化、結束)
- 支持傳遞參數到事件回調中
安裝方法
在 uni-app 插件市場中搜索 jia-countdown-verify
并導入到項目中。
基礎用法
<template><view><jia-countdown-verify ref="countdownBtn" @send="onSend" /></view>
</template><script>
export default {methods: {onSend() {// 發送驗證碼邏輯// 成功后調用組件的 success 方法開始倒計時this.$refs.countdownBtn.success();}}
}
</script>
高級用法
使用 successVal 和 resetVal 控制倒計時
<template><view><input type="text" v-model="phone" placeholder="請輸入手機號" /><jia-countdown-verify@send="sendCode":successVal="successCount":resetVal="resetCount"/></view>
</template><script>
export default {data() {return {phone: "",successCount: 0, // 成功計數器resetCount: 0, // 重置計數器};},methods: {sendCode() {// 驗證手機號if (!/^1\d{10}$/.test(this.phone)) {uni.showToast({title: "請輸入正確的手機號",icon: "none",});// 增加重置計數器觸發重置this.resetCount++;return;}// 模擬API請求setTimeout(() => {// 發送成功,增加成功計數器觸發倒計時this.successCount++;}, 1000);}}
}
</script>
API
Props
屬性名 | 類型 | 默認值 | 說明 |
---|---|---|---|
text | String | “發送驗證碼” | 按鈕默認文本 |
sendText | String | “請稍候…” | 發送中的按鈕文本 |
countdownText | String | “s后獲取” | 倒計時文本后綴 |
seconds | Number | 60 | 倒計時秒數 |
width | String | “182rpx” | 按鈕寬度 |
height | String | “56rpx” | 按鈕高度 |
padding | String | “0” | 按鈕內邊距 |
margin | String | “0” | 按鈕外邊距 |
radius | String | “6rpx” | 按鈕圓角 |
size | Number | 24 | 字體大小(rpx) |
color | String | “#5677fc” | 字體顏色 |
background | String | “transparent” | 背景顏色 |
borderWidth | String | “1px” | 邊框寬度 |
borderColor | String | “#5677fc” | 邊框顏色 |
isOpacity | Boolean | true | 倒計時狀態是否透明 |
hover | Boolean | true | 是否有點擊效果 |
successVal | Number/String | 0 | 觸發倒計時的值,值變化時開始倒計時 |
resetVal | Number/String | 0 | 重置倒計時的值,值變化時重置倒計時 |
start | Boolean | false | 是否自動開始倒計時 |
params | Number/String | 0 | 傳遞給事件的參數 |
disabledColor | String | “” | 禁用狀態的背景顏色 |
Events
事件名 | 說明 | 回調參數 |
---|---|---|
send | 點擊發送按鈕時觸發 | { params: 傳入的params值 } |
countdown | 倒計時變化時觸發 | { seconds: 剩余秒數, params: 傳入的params值 } |
end | 倒計時結束時觸發 | { params: 傳入的params值 } |
Methods
方法名 | 說明 | 參數 |
---|---|---|
success | 開始倒計時 | - |
reset | 重置倒計時狀態 | - |
使用示例
默認使用
<jia-countdown-verify ref="sms1" @send="onSend" />
默認為倒計時狀態
<jia-countdown-verify :start="true" @send="onSend" />
設置圓角
<jia-countdown-verify :radius="'20rpx'" @send="onSend" />
設置顏色
<jia-countdown-verifycolor="#fff"background="#000"borderWidth="0"@send="onSend"
/>
設置大小
<jia-countdown-verify:width="'300rpx'":height="'60rpx'"@send="onSend"
/>
設置秒數
<jia-countdown-verify :seconds="120" @send="onSend" />
改變倒計時狀態下顏色
<jia-countdown-verifybackground="#02B653"borderWidth="0"color="#fff"@send="onSend"disabledColor="#999"
/>
設置文本
<jia-countdown-verifytext="發送驗證碼短信"countdownText="秒后可重發"@send="onSend"
/>
注意事項
- 當使用
ref
手動控制倒計時時,需要在發送驗證碼成功后調用success()
方法開始倒計時 - 當使用
successVal
和resetVal
控制倒計時時,只需改變這兩個值即可觸發相應操作 - 組件內部會在銷毀時自動清除定時器,無需手動處理
- 倒計時過程中按鈕會自動禁用,防止重復點擊
組件封裝中細節點總結
- 微信小程序兼容:style=“[styleObj]” 需要 統一使用數組包裹樣式對象
- 慎用 upx 單位:僅在維護老項目或已有組件庫時,才需繼續使用 upx;新開發應盡量避免使用 upx,并可逐步將 upx 單位改為 rpx,如果確實需要動態計算 upx 值,可調用 uni.upx2px()。
- 在 Vue3 中為所有自定義事件聲明 emits,避免與原生事件沖突
- 生命周期兼容處理 vue2 beforeDestroy vue3 unmounted 使用注釋做環境區分 // #ifdef VUE2, // #endif
完整代碼
建議通過插件市場下載小編持續維護
<template><!-- 驗證碼倒計時按鈕 --><buttonclass="sms-btn":disabled="isDisabled":hover-class="hover ? 'button-hover' : 'none'"@click="handleClick":style="[buttonStyle]">{{ buttonText }}</button>
</template><script>
/*** 驗證碼倒計時按鈕組件* @description 用于發送短信驗證碼的倒計時按鈕,支持自定義樣式和倒計時時間* @property {String} text - 按鈕默認文本* @property {String} sendText - 發送中的按鈕文本* @property {String} countdownText - 倒計時文本后綴* @property {Number} seconds - 倒計時秒數* @property {String} width - 按鈕寬度* @property {String} height - 按鈕高度* @property {String} padding - 按鈕內邊距* @property {String} margin - 按鈕外邊距* @property {String} radius - 按鈕圓角* @property {Number} size - 字體大小* @property {String} color - 字體顏色* @property {String} background - 背景顏色* @property {String} borderWidth - 邊框寬度* @property {String} borderColor - 邊框顏色* @property {Boolean} isOpacity - 倒計時狀態是否透明* @property {Boolean} hover - 是否有點擊效果* @property {Number/String} successVal - 觸發倒計時的值,值變化時開始倒計時* @property {Number/String} resetVal - 重置倒計時的值,值變化時重置倒計時* @property {Boolean} start - 是否自動開始倒計時* @property {Number/String} params - 傳遞給事件的參數* @event {Function} send - 點擊發送按鈕時觸發* @event {Function} countdown - 倒計時變化時觸發* @event {Function} end - 倒計時結束時觸發*/
export default {name: "SmsCountdownButton",/*** Vue3 現在提供了一個emits選項,類似于現有props選項。此選項可用于定義組件可以向其父對象發出的事件強烈建議使用emits記錄每個組件發出的所有事件。這一點特別重要,因為去除了.native修飾符。emits 現在在未使用聲明的事件的所有偵聽器都將包含在組件的中$attrs,默認情況下,該偵聽器將綁定到組件的根節點。*/emits: ["countdown", "send", "end"], // 顯式聲明自定義事件props: {text: { type: String, default: "發送驗證碼" }, // 按鈕默認文本sendText: { type: String, default: "請稍候..." }, // 發送中的按鈕文本countdownText: { type: String, default: "s后獲取" }, // 倒計時文本后綴seconds: { type: Number, default: 60 }, // 倒計時秒數width: { type: String, default: "182rpx" }, // 按鈕寬度height: { type: String, default: "56rpx" }, // 按鈕高度padding: { type: String, default: "0" }, // 按鈕內邊距margin: { type: String, default: "0" }, // 按鈕外邊距radius: { type: String, default: "6rpx" }, // 按鈕圓角size: { type: Number, default: 24 }, // 字體大小color: { type: String, default: "#5677fc" }, // 字體顏色background: { type: String, default: "transparent" }, // 背景顏色borderWidth: { type: String, default: "1px" }, // 邊框寬度borderColor: { type: String, default: "#5677fc" }, // 邊框顏色isOpacity: { type: Boolean, default: true }, // 倒計時狀態是否透明hover: { type: Boolean, default: true }, // 是否有點擊效果successVal: { type: [Number, String], default: 0 }, // 觸發倒計時的值resetVal: { type: [Number, String], default: 0 }, // 重置倒計時的值start: { type: Boolean, default: false }, // 是否自動開始倒計時params: { type: [Number, String], default: 0 }, // 傳遞給事件的參數disabledColor: { type: String, default: "" }, // 禁用狀態的字體顏色},data() {return {state: "idle", // 按鈕狀態:idle(空閑)、pending(發送中)、countdown(倒計時)remaining: this.seconds, // 剩余秒數timer: null, // 定時器};},computed: {/*** 按鈕是否禁用* @return {Boolean} 非空閑狀態時禁用按鈕*/isDisabled() {return this.state !== "idle";},/*** 按鈕文本* @return {String} 根據狀態返回不同的按鈕文本*/buttonText() {// 空閑狀態if (this.state === "idle") {return this.text;// 發送狀態} else if (this.state === "pending") {return this.sendText;// 倒計時狀態} else if (this.state === "countdown") {return `${this.remaining}${this.countdownText}`;}},/*** 按鈕樣式* @return {Object} 樣式對象*/buttonStyle() {const style = {width: this.width,height: this.height,padding: this.padding,margin: this.margin,color: this.color,background: this.background,borderWidth: this.borderWidth,borderColor: this.borderColor,borderRadius: this.radius,fontSize: this.size + "rpx",borderStyle: "solid",textAlign: "center",};// 倒計時狀態且需要透明時設置透明度if (this.state === "countdown" && this.isOpacity) {style.opacity = 0.5;}// 倒計時狀態且需要禁用時設置背景顏色if (this.disabledColor && this.state === "countdown") {style.background = this.disabledColor;}return style;},},watch: {/*** 監聽成功值變化,觸發倒計時*/successVal(newVal, oldVal) {if (newVal !== oldVal) {this.success();}},/*** 監聽重置值變化,重置倒計時*/resetVal(newVal, oldVal) {if (newVal !== oldVal) {this.reset();}},},mounted() {// 如果設置了自動開始,則立即開始倒計時if (this.start) {this.success();}},// 在 Vue3 中組件卸載的生命周期被重新命名 destroyed 修改為 unmounted// #ifdef VUE2beforeDestroy() {// 組件銷毀前清除定時器if (this.timer) {clearInterval(this.timer);this.timer = null;}},// #endif// #ifdef VUE3unmounted() {// 組件銷毀前清除定時器if (this.timer) {clearInterval(this.timer);this.timer = null;}},// #endifmethods: {/*** 開始倒計時*/startCountdown() {// 清除可能存在的定時器if (this.timer) {clearInterval(this.timer);}// 設置狀態為倒計時this.state = "countdown";this.remaining = this.seconds;// 觸發倒計時事件 {因為倒計時事件是每秒觸發一次,最開始要觸發一次}this.$emit("countdown", { seconds: this.remaining, params: this.params });// 設置定時器this.timer = setInterval(() => {// 倒計時this.remaining--;if (this.remaining > 0) {// 每秒觸發倒計時事件this.$emit("countdown", {seconds: this.remaining,params: this.params,});} else {// 倒計時結束,清除定時器clearInterval(this.timer);this.timer = null;// 設置狀態為空閑this.state = "idle";// 觸發結束事件this.$emit("end", { params: this.params });}}, 1000);},/*** 成功發送驗證碼,開始倒計時*/success() {// 如果按鈕狀態不為倒計時,則開始倒計時 [空閑狀態|發送中狀態都可以進入]// 自動開始時是空閑,手動點擊時是發送中if (this.state !== "countdown") {this.startCountdown();}},/*** 重置按鈕狀態*/reset() {// 清除定時器if (this.timer) {clearInterval(this.timer);this.timer = null;}// 重置狀態this.state = "idle";// 重置剩余秒數this.remaining = this.seconds;},/*** 按鈕點擊處理*/handleClick() {// 如果按鈕狀態為空閑,則設置狀態為發送中,并觸發發送事件if (this.state === "idle") {// 設置狀態為發送中this.state = "pending";// 觸發發送事件this.$emit("send", { params: this.params });}},},
};
</script><style scoped>
/* 按鈕基本樣式 */
.sms-btn {display: inline-block; /* 內聯塊級元素 */text-align: center; /* 文本居中 */cursor: pointer; /* 鼠標樣式 */
}
/* 禁用狀態樣式 */
.sms-btn:disabled {cursor: not-allowed; /* 禁用狀態的鼠標樣式 */
}
.button-hover {transform: scale(0.98); /* 按鈕懸停時的縮放 */box-shadow: 0 2px 5px rgba(0,0,0,0.2); /* 按鈕懸停時的陰影 */
}</style>