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-verify
color="#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-verify
background="#02B653"
borderWidth="0"
color="#fff"
@send="onSend"
disabledColor="#999"
/>
设置文本
<jia-countdown-verify
text="发送验证码短信"
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>
<!-- 验证码倒计时按钮 -->
<button
class="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 VUE2
beforeDestroy() {
// 组件销毁前清除定时器
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
},
// #endif
// #ifdef VUE3
unmounted() {
// 组件销毁前清除定时器
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
},
// #endif
methods: {
/**
* 开始倒计时
*/
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>