组件介绍
这是一个用于获取验证码的倒计时按钮组件,支持自定义倒计时时间、按钮样式和文字格式。
基本用法
javascript
<countdown-verify
seconds="60"
button-text="获取验证码"
bind:send="onSendVerifyCode"
/>
属性说明
属性名 | 类型 | 默认值 | 说明 |
---|---|---|---|
seconds | Number | 60 | 倒计时总时长(秒),必须大于0 |
buttonText | String | "获取验证码" | 按钮默认显示的文字 |
countdownFormat | String | "剩余%s秒" | 倒计时过程中显示的文字格式,%s会被替换为剩余秒数 |
buttonStyle | String | "" | 按钮的样式,支持内联样式 |
disabledStyle | String | "background-color: #cccccc; color: #ffffff;" | 倒计时过程中按钮的样式 |
instanceId | String | "" | 组件实例ID,用于多实例区分,不传会自动生成 |
事件说明
事件名 | 说明 | 参数 |
---|---|---|
send | 点击获取验证码按钮时触发 | { instanceId: string } |
start | 倒计时开始时触发 | { instanceId: string } |
end | 倒计时结束时触发 | { instanceId: string } |
方法说明
方法名 | 说明 | 参数 | 返回值 |
---|---|---|---|
start() | 开始倒计时 | 无 | 无 |
stop() | 停止倒计时 | 无 | 无 |
reset() | 重置倒计时 | 无 | 无 |
getStatus() | 获取当前状态 | 无 | { isCounting: boolean, remaining: number, instanceId: string } |
使用示例
javascript
Page({
data: {
// ...
},
onSendVerifyCode(e) {
// 发送验证码请求
wx.request({
url: 'your-api-url',
success: () => {
// 请求成功后开始倒计时
this.selectComponent('#verifyCode').start();
}
});
}
});
注意事项
组件会自动处理倒计时过程中的状态切换
倒计时过程中按钮会被禁用
组件销毁时会自动清理定时器
支持多个实例同时使用,每个实例都有唯一的instanceId
倒计时时间必须大于0,否则会自动设置为60秒
样式定制
可以通过 buttonStyle 和 disabledStyle 属性来自定义按钮样式,支持所有CSS属性。
javascript
<countdown-verify
button-style="background-color: #007AFF; color: white; border-radius: 4px;"
disabled-style="background-color: #999999; color: white;"
/>
完整代码
js
javascript
// components/countdown-verify/countdown-verify.js
Component({
properties: {
// 倒计时总时长(秒)
seconds: {
type: Number,
value: 60,
observer: function (newVal) {
if (newVal <= 0) {
console.warn("倒计时时间必须大于0");
this.setData({ seconds: 60 });
}
},
},
// 按钮默认文字
buttonText: {
type: String,
value: "获取验证码",
},
// 禁用状态下的文字格式
countdownFormat: {
type: String,
value: "剩余%s秒",
},
// 按钮样式
buttonStyle: {
type: String,
value: "",
},
// 禁用状态按钮样式
disabledStyle: {
type: String,
value: "background-color: #cccccc; color: #ffffff;",
},
// 实例ID,用于多实例区分
instanceId: {
type: String,
value: "",
},
},
data: {
remaining: 0,
isCounting: false,
timer: null,
displayText: "",
},
lifetimes: {
attached() {
// 生成唯一实例ID
if (!this.properties.instanceId) {
this.setData({
instanceId:
"countdown_" +
Date.now() +
"_" +
Math.random().toString(36).substr(2),
});
}
this.updateDisplayText();
},
detached() {
this.clearTimer();
},
},
// 监听倒计时和是否正在倒计时,更新显示文本
observers: {
"remaining, isCounting": function (remaining, isCounting) {
this.updateDisplayText();
},
},
methods: {
// 更新显示文本
updateDisplayText() {
const text = this.data.isCounting
? this.properties.countdownFormat.replace("%s", this.data.remaining)
: this.properties.buttonText;
this.setData({ displayText: text });
},
// 开始倒计时
start() {
if (this.data.isCounting) {
console.warn("倒计时正在进行中");
return;
}
this.clearTimer();
this.setData({
isCounting: true,
remaining: this.properties.seconds,
});
this.data.timer = setInterval(() => {
const remaining = this.data.remaining - 1;
if (remaining <= 0) {
this.stop();
return;
}
this.setData({ remaining });
}, 1000);
this.triggerEvent("start", { instanceId: this.data.instanceId });
},
// 停止倒计时
stop() {
this.clearTimer();
this.setData({
isCounting: false,
remaining: 0,
});
this.triggerEvent("end", { instanceId: this.data.instanceId });
},
// 清除定时器
clearTimer() {
if (this.data.timer) {
clearInterval(this.data.timer);
this.data.timer = null;
}
},
// 按钮点击事件
handleTap() {
if (!this.data.isCounting) {
this.triggerEvent("send", { instanceId: this.data.instanceId });
}
},
// 重置倒计时
reset() {
this.stop();
},
// 获取当前状态
getStatus() {
return {
isCounting: this.data.isCounting,
remaining: this.data.remaining,
instanceId: this.data.instanceId,
};
},
},
});
wxml
xml
<!-- components/countdown-verify/countdown-verify.wxml -->
<button style="{{isCounting ? disabledStyle : buttonStyle}}" disabled="{{isCounting}}" bind:tap="handleTap" aria-label="{{isCounting ? '倒计时中' : buttonText}}" data-instance-id="{{instanceId}}">
{{displayText}}
</button>
wxss
xml
/* components/countdown-verify/countdown-verify.wxss */
button {
margin: 0;
padding: 0;
border: none;
background: none;
font-size: 28rpx;
line-height: 1.5;
text-align: center;
border-radius: 8rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
min-width: 180rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
}
button[disabled] {
opacity: 0.6;
}
button::after {
border: none;
}
json
xml
{
"component": true,
"usingComponents": {}
}