Vant 4 CountDown 倒计时组件完全指南:从毫秒级渲染到实例方法控制
2026/9/13 1:15:16 网站建设 项目流程

Vant 4 CountDown 倒计时组件完全指南:从毫秒级渲染到实例方法控制

【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vant

CountDown 是 Vant 4 移动端组件库中用于实时展示倒计时数值的组件,支持毫秒级精度与自定义时间格式。本文将以 CountDown 官方文档 为主线,结合组件源码、@vant/useuseCountDown的底层实现与测试用例,系统讲解倒计时的引入、五种典型用法、完整 API 与主题定制方案,帮助你在秒杀、活动开售、验证码重发、答题限时等移动端场景中快速落地可靠的倒计时能力。

组件能力概览与引入方式

CountDown 组件定位轻量:核心源码仅由一个 CountDown.tsx 渲染组件与一个 utils.ts 格式化工具组成,全部时间计算逻辑下沉到独立的组合式函数useCountDown,组件层保持高度精简。

通过以下方式即可全局注册组件,更多注册方式(如局部注册、按需引入)可参考 组件注册指南:

import { createApp } from 'vue'; import { CountDown } from 'vant'; const app = createApp(); app.use(CountDown);

注册后即可在模板中使用<van-count-down>标签。同时,index.ts 中声明了VanCountDown的全局组件类型,配合 Volar 可在模板中获得完整的类型提示与属性校验。

基础用法:以time为核心

time属性表示倒计时总时长,单位为毫秒。下面的示例创建了一个 30 小时的倒计时:

<van-count-down :time="time" />
import { ref } from 'vue'; export default { setup() { const time = ref(30 * 60 * 60 * 1000); return { time }; }, };

组件在挂载时即通过watch(() => props.time, resetTime, { immediate: true })监听time的变化,CountDown.tsx 中一旦time属性变化就会重置剩余时间;若auto-starttrue则重置后自动开始。因此动态修改time即可实现"重置为新的时长"的常见需求。

需要说明的是,组件根节点渲染了role="timer"无障碍属性,方便屏幕阅读器识别倒计时区域。

自定义格式:format 的解析规则

通过format属性可以完全控制倒计时文本的内容,例如:

<van-count-down :time="time" format="DD 天 HH 时 mm 分 ss 秒" />

format支持以下占位符,各占位符都会被零填充(如05):

格式说明
DD天数
HH小时
mm分钟
ss秒数
S毫秒(1 位)
SS毫秒(2 位)
SSS毫秒(3 位)

默认值为HH:mm:ss。这里有两个值得留意的行为:

  • 毫秒占位符按从长到短的顺序匹配:先匹配SSS,再匹配SS,最后匹配单个S,取毫秒值的前 1 或前 2 位展示;
  • 当 format 中省略了某个高位单位时,该单位会被"折算"进下一个单位。这一逻辑实现在 utils.ts 的parseFormat中:
if (format.includes('DD')) { format = format.replace('DD', padZero(days)); } else { hours += days * 24; // 未使用 DD 时,天数折算进小时 } // HH / mm / ss 同理逐级折算

也就是说,若 format 不含DD,小时会包含"天数 × 24";若不含HH,分钟会折算 "小时 × 60";若不含mm,秒数会折算 "分钟 × 60";若不含ss,则毫秒会包含 "秒 × 1000"。这一规则保证了任何省略写法下总时长都不会丢失,测试用例should format incomplete time correctly(test/index.spec.tsx)专门验证了省略天数的折算行为。

毫秒级渲染:microTick 与 macroTick 的分工

倒计时默认每秒渲染一次;开启millisecond属性后即切换为毫秒级渲染:

<van-count-down millisecond :time="time" format="HH:mm:ss:SS" />

两种渲染模式由useCountDown内部的tick决定(packages/vant-use/src/useCountDown/index.ts):

  • 毫秒模式:调用microTick,每个requestAnimationFrame回调中都重新计算剩余时间并更新视图,保证毫秒位实时跳动;
  • 秒级模式:调用macroTick,利用isSameSecond判断秒数是否变化,同一秒内不触发重复渲染,大幅降低无效渲染开销。

同时,tick中通过inBrowser判断在服务端(SSR)环境下不启动计时,避免水合不一致的问题。两种模式均以endTime = Date.now() + remain.value为基准计算Math.max(endTime - Date.now(), 0)得出剩余时间,因此即便requestAnimationFrame被节流,最终时间也不会漂移,比逐帧递减remain更准确。

自定义样式:插槽与 timeData

通过默认插槽可以完全自定义倒计时的外观,插槽参数timeDataCurrentTime对象,字段含义见下文 API 表格:

<van-count-down :time="time"> <template #default="timeData"> <span class="block">{{ timeData.hours }}</span> <span class="colon">:</span> <span class="block">{{ timeData.minutes }}</span> <span class="colon">:</span> <span class="block">{{ timeData.seconds }}</span> </template> </van-count-down> <style> .colon { display: inline-block; margin: 0 4px; color: #1989fa; } .block { display: inline-block; width: 22px; color: #fff; font-size: 12px; text-align: center; background-color: #1989fa; } </style>

从 CountDown.tsx 可以看到,渲染逻辑为:存在默认插槽时优先渲染插槽内容(传入current.value),否则渲染parseFormat格式化后的纯文本。因此插槽方案与 format 方案二选一,插槽方案适合将数字渲染为色块、胶囊、图片等富样式。仓库中的官方示例 demo/index.vue 还在此基础上加入了圆角与主题色变量,可作为参考。

手动控制:start / pause / reset

通过 ref 获取组件实例后,可以调用startpausereset三个实例方法,实现按钮驱动的倒计时:

<van-count-down ref="countDown" millisecond :time="3000" :auto-start="false" format="ss:SSS" @finish="onFinish" /> <van-grid clickable> <van-grid-item text="开始" icon="play-circle-o" @click="start" /> <van-grid-item text="暂停" icon="pause-circle-o" @click="pause" /> <van-grid-item text="重置" icon="replay" @click="reset" /> </van-grid>
import { showToast } from 'vant'; export default { setup() { const countDown = ref(null); const start = () => { countDown.value.start(); }; const pause = () => { countDown.value.pause(); }; const reset = () => { countDown.value.reset(); }; const onFinish = () => showToast('倒计时结束'); return { start, pause, reset, onFinish, countDown, }; }, };

三个方法的行为与底层实现对应如下(详见 packages/vant-use/src/useCountDown/index.ts):

方法名说明参数返回值
start开始倒计时;以当前剩余时间重新锚定endTime,已结束时调用则从 0 继续--
pause暂停倒计时,取消当前rafId并保持剩余时间--
reset重设倒计时为time属性值;若auto-starttrue,重设后会自动开始--

组件通过useExpose(packages/vant/src/composables/use-expose.ts)将这三个方法挂载到组件实例的 proxy 上,因此模板中ref="countDown"拿到的实例可以直接调用。测试用例对上述三种操作均做了覆盖:should start counting after calling the start methodshould pause counting after calling the pause methodshould reset time after calling the reset method(见 test/index.spec.tsx)。

另外,useCountDown还通过onActivated/onDeactivated钩子与<KeepAlive>协同:组件被缓存停用时自动暂停、重新激活时自动续跑,测试用例should pause counting when deactivated验证了该行为,在列表页与详情页间切换的场景下可避免倒计时被错误推进。

API 参考

Props

参数说明类型默认值
time倒计时时长,单位毫秒number | string0
format时间格式stringHH:mm:ss
auto-start是否自动开始倒计时booleantrue
millisecond是否开启毫秒级渲染booleanfalse

time在 CountDown.tsx 中通过makeNumericProp(0)声明,因此字符串类型的数字也会被正确转换为number后传入useCountDown

Events

事件名说明回调参数
finish倒计时结束时触发-
change倒计时变化时触发currentTime: CurrentTime

finishchange分别由useCountDownonFinishonChange回调转发。setRemain中当剩余时间为 0 时会自动pause并触发finishchange则在每次剩余时间更新时触发,回调参数为完整的CurrentTime对象,测试用例should emit change event when counting验证了其参数结构。

Slots

名称说明参数
default自定义内容currentTime: CurrentTime

CurrentTime 格式

名称说明类型
total剩余总时间(单位毫秒)number
days剩余天数number
hours剩余小时number
minutes剩余分钟number
seconds剩余秒数number
milliseconds剩余毫秒number

该对象由 packages/vant-use/src/useCountDown/index.ts 的parseTime基于DAY / HOUR / MINUTE / SECOND常量逐级取整生成,total始终等于原始剩余毫秒数。

类型定义

组件导出以下类型定义,便于在 TypeScript 项目中获得强类型支持:

import type { CountDownProps, CountDownInstance, CountDownCurrentTime, } from 'vant';

CountDownInstance是组件实例的类型,用法如下:

import { ref } from 'vue'; import type { CountDownInstance } from 'vant'; const countDownRef = ref<CountDownInstance>(); countDownRef.value?.start();

从 types.ts 可以看到,CountDownInstance基于ComponentPublicInstance<CountDownProps, CountDownExpose>构造,其中CountDownExpose定义了startpausereset三个实例方法的签名;CountDownCurrentTime则直接复用@vant/useCurrentTime类型。TS 环境下建议将 demo 中的ref(null)写法替换为ref<CountDownInstance>()以获得方法调用时的完整提示。

主题定制

组件通过 index.less 提供了三个 CSS 变量,可在根节点或通过 ConfigProvider 组件 统一覆盖,实现与业务主题色的联动:

名称默认值描述
--van-count-down-text-colorvar(--van-text-color)文本颜色
--van-count-down-font-sizevar(--van-font-size-md)字号
--van-count-down-line-heightvar(--van-line-height-md)行高

这三个变量默认值均引用 Vant 全局基础变量,因此在不做任何配置时倒计时文本会自动跟随主题风格;自定义时只需在组件外层覆盖同名变量即可,例如配合插槽方案渲染的彩色数字块时,可同步调整字号与行高保证数字块间距统一。

常见问题

在 iOS 系统上倒计时不生效?

如果你遇到了在 iOS 上倒计时不生效的问题,请确认在创建 Date 对象时没有使用new Date('2020-01-01')这样的写法。iOS 的 JavaScript 引擎不支持以中划线(-)分隔的日期字符串格式,解析会得到Invalid Date,进而导致所有时间计算返回NaN;正确写法是使用斜杠分隔的new Date('2020/01/01'),或将日期拆分为参数形式new Date(2020, 0, 1)。由于 CountDown 内部以Date.now()作为计时基准,若业务侧传入的结束时间先经过错误的 Date 解析,就会表现为"倒计时不生效",排查时可优先检查结束时间的构造方式。

若需要基于某个"未来时间点"而非时长运行倒计时,可先计算endTime.getTime() - Date.now()得到毫秒差,再作为time传入组件,同时注意遵循上述 iOS 兼容的日期构造写法。

【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vant

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询