Appearance
BizCountdownButton 倒计时按钮
点击后立即禁用并显示「xx 秒后重发」,倒计时结束自动恢复,可重新点击。用于验证码发送、失败重试防连点、敏感操作冷却。type / size / plain 等属性透传内部 el-button。
基础用法
duration 控制秒数(示例 10s);手机号校验不通过时 reset() 立即恢复按钮。<script setup lang="ts">
/** 基础用法:验证码发送(10s 快速演示)+ 编程式 reset */
import { ref } from 'vue'
import { ElButton, ElInput, ElMessage } from 'element-plus'
import { BizCountdownButton } from 'vue3-ep-biz-lib'
import type { BizCountdownButtonInstance } from 'vue3-ep-biz-lib'
const mobile = ref('')
const btnRef = ref<BizCountdownButtonInstance>()
const onSend = (): void => {
if (!/^1\d{10}$/.test(mobile.value)) {
ElMessage.warning('请输入正确的手机号')
btnRef.value?.reset()
return
}
ElMessage.success('验证码已发送(示例)')
}
</script>
<template>
<div style="display: flex; gap: 12px; align-items: center; max-width: 420px">
<ElInput v-model="mobile" placeholder="请输入手机号" style="max-width: 200px" />
<BizCountdownButton ref="btnRef" type="primary" plain :duration="10" @click="onSend" />
<ElButton link type="primary" @click="btnRef?.reset()">重置</ElButton>
</div>
</template>
显示代码
文案定制与编程式控制
start-text / counting-text({time} 占位)/ end-text 全量文案定制;start(seconds) 编程式进入任意时长倒计时、stop() 冻结当前状态、reset() 恢复初始;end 事件在倒计时结束时触发(常用于刷新可重试状态)。<script setup lang="ts">
/** 进阶:全量文案自定义({time} 占位)、编程式 start(seconds) / stop / reset、end 事件、按钮样式 attrs */
import { ref } from 'vue'
import { ElButton, ElMessage } from 'element-plus'
import { BizCountdownButton } from 'vue3-ep-biz-lib'
import type { BizCountdownButtonInstance } from 'vue3-ep-biz-lib'
const btnRef = ref<BizCountdownButtonInstance>()
const onEnd = (): void => {
ElMessage.success('冷却结束,可重新发起重试')
}
</script>
<template>
<div style="display: flex; gap: 12px; align-items: center; flex-wrap: wrap; max-width: 560px">
<BizCountdownButton
ref="btnRef"
type="warning"
size="small"
round
:duration="8"
start-text="立即重试"
counting-text="{time} 秒后可再次重试"
end-text="重新发起"
@end="onEnd"
/>
<ElButton size="small" @click="btnRef?.start(15)">start(15):进入 15s 倒计时</ElButton>
<ElButton size="small" @click="btnRef?.stop()">stop():冻结当前状态</ElButton>
<ElButton size="small" @click="btnRef?.reset()">reset():恢复初始</ElButton>
</div>
</template>
显示代码
验证码倒计时持久化(storage-key)
storage-key="demo-sms-cooldown":点击发送后刷新当前页面(F5),按钮仍显示剩余秒数—— 结束时间戳持久化在 localStorage,倒计时自然结束或 reset() 后自动清除。真实高频痛点:用户输错验证码刷新页面重填,若无持久化会被反复触发短信。
验证码高频痛点:用户输错刷新页面重填,倒计时不应归零放行重发。
storage-key 将结束时间戳存 localStorage,刷新 / 重开页面自动恢复剩余秒数,倒计时自然结束或 reset() 后清除。<script setup lang="ts">
/** 场景:验证码倒计时持久化——点击后刷新页面,倒计时不归零(storageKey) */
import { ElButton, ElMessage } from 'element-plus'
import { BizCountdownButton } from 'vue3-ep-biz-lib'
const onEnd = (): void => {
ElMessage.success('冷却结束,可重新发送')
}
</script>
<template>
<div style="max-width: 520px">
<BizCountdownButton
type="primary"
:duration="60"
storage-key="demo-sms-cooldown"
@end="onEnd"
/>
<div style="margin-top: 12px; font-size: 13px; color: var(--el-text-color-secondary)">
storage-key="demo-sms-cooldown":点击发送后<strong>刷新当前页面(F5)</strong>,按钮仍显示剩余秒数——
结束时间戳持久化在 localStorage,倒计时自然结束或 reset() 后自动清除。真实高频痛点:用户输错验证码刷新页面重填,若无持久化会被反复触发短信。
</div>
<div style="margin-top: 8px">
<ElButton size="small" @click="ElMessage.info('请点击上方按钮进入倒计时后刷新页面验证')">
操作提示
</ElButton>
</div>
</div>
</template>
显示代码
邮箱激活重发
激活邮件已发送至 dev@example.cn,
注册流程:激活邮件 30s 冷却,start / counting / end 三段文案完整定制(link 弱样式不抢视觉)。
<script setup lang="ts">
/** 场景:邮箱激活邮件重发——倒计时 + 结束提示文案定制 */
import { ElMessage } from 'element-plus'
import { BizCountdownButton } from 'vue3-ep-biz-lib'
const onEnd = (): void => {
ElMessage.info('可以重新发送激活邮件了')
}
</script>
<template>
<div style="display: flex; gap: 12px; align-items: center; max-width: 520px">
<span style="font-size: 13px; color: var(--el-text-color-secondary)">激活邮件已发送至 dev@example.cn,</span>
<BizCountdownButton
type="primary"
link
:duration="30"
start-text="重新发送邮件"
counting-text="邮件 {time}s 后可重发"
end-text="再次发送激活邮件"
@end="onEnd"
/>
</div>
</template>
显示代码
失败重试冷却
失败后进入冷却防雪崩:避免下游故障时的重试风暴
同步场景:失败进入 10s 冷却防重试风暴(countingText=「冷却中 {time}s」),成功后按钮永久 disabled。
<script setup lang="ts">
/** 场景:接口失败重试冷却——点击调接口,失败进入 10s 冷却 */
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import { BizCountdownButton } from 'vue3-ep-biz-lib'
const state = ref<'idle' | 'cooling' | 'ok'>('idle')
const onRetry = (): void => {
if (state.value === 'cooling') return
/* 模拟:前两次失败,第三次成功 */
state.value = Math.random() > 0.4 ? 'ok' : 'cooling'
if (state.value === 'ok') {
ElMessage.success('同步成功')
} else {
ElMessage.error('同步失败:连接超时,10s 后可重试')
}
}
</script>
<template>
<div style="display: flex; gap: 12px; align-items: center; max-width: 520px">
<BizCountdownButton
type="warning"
plain
size="small"
:duration="10"
start-text="立即同步"
counting-text="冷却中 {time}s"
end-text="重试同步"
:disabled="state === 'ok'"
@click="onRetry"
/>
<span style="font-size: 13px; color: var(--el-text-color-secondary)">
{{ state === 'ok' ? '数据已同步,无需重试' : '失败后进入冷却防雪崩:避免下游故障时的重试风暴' }}
</span>
</div>
</template>
显示代码
协议强阅读
1.1 本协议是您与示例公司之间关于使用本服务所订立的契约…… 1.2 您应遵守相关法律法规,不得利用本服务从事违法违规活动…… 1.3 我们将按《隐私政策》收集与使用必要信息……(滚动即视为阅读)
合规场景:倒计时结束(end 事件)才解锁「同意协议」勾选框——防秒勾的轻量实现。
<script setup lang="ts">
/** 场景:注册协议强阅读——倒计时结束才可勾选同意 */
import { ref } from 'vue'
import { ElButton, ElCheckbox, ElMessage } from 'element-plus'
import { BizCountdownButton } from 'vue3-ep-biz-lib'
const readDone = ref(false)
const agreed = ref(false)
const onSubmit = (): void => {
if (!agreed.value) {
ElMessage.warning('请先勾选同意《服务协议》')
return
}
ElMessage.success('注册成功(示例)')
}
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 12px; max-width: 420px; padding: 14px; border: 1px solid var(--el-border-color-lighter); border-radius: 6px">
<div style="height: 88px; overflow-y: auto; padding: 8px 10px; background: var(--el-fill-color-light); border-radius: 4px; font-size: 13px; line-height: 1.8">
1.1 本协议是您与示例公司之间关于使用本服务所订立的契约…… 1.2 您应遵守相关法律法规,不得利用本服务从事违法违规活动…… 1.3 我们将按《隐私政策》收集与使用必要信息……(滚动即视为阅读)
</div>
<div style="display: flex; align-items: center; gap: 12px">
<BizCountdownButton
v-if="!readDone"
size="small"
:duration="8"
start-text="开始阅读(8s)"
counting-text="阅读中,剩余 {time}s"
@end="readDone = true"
/>
<ElCheckbox v-model="agreed" :disabled="!readDone">我已阅读并同意《服务协议》</ElCheckbox>
</div>
<ElButton type="primary" @click="onSubmit">立即注册</ElButton>
</div>
</template>
显示代码
Props
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| duration | number | 60 | 倒计时秒数 |
| start-text | string | '发送验证码' | 初始文案 |
| counting-text | string | '{time}s 后重发' | 倒计时中文案,{time} 为剩余秒数占位 |
| end-text | string | '重新发送' | 倒计时结束后文案 |
| disabled | boolean | false | 禁用(与倒计时互不影响) |
| storage-key | string | — | 倒计时持久化:结束时间戳存 localStorage,刷新/重开页面自动恢复剩余秒数,结束后清除 |
其余 attrs 透传内部 el-button。
Events
| 事件名 | 参数 | 说明 |
|---|---|---|
| click | (event: MouseEvent) | 点击(随即进入倒计时) |
| end | — | 倒计时结束 |
Slots
| 插槽名 | 说明 |
|---|---|
| default | 覆盖按钮文案(默认按状态自动显示) |
Expose
| 属性/方法 | 说明 |
|---|---|
| start(seconds?) | 编程式进入倒计时(可覆盖秒数) |
| reset() | 中止倒计时并回初始文案 |
| stop() | 仅停止倒计时(保持当前文案状态) |