CountDown 倒计时 - Vant 4
⏰ CountDown 倒计时
⏳ 介绍
时间就像流水一样珍贵,CountDown 倒计时组件就是你的专属时间管家!⏰ 它能够精确到毫秒地展示倒计时,就像一个永不疲倦的时间守护者。
无论是激动人心的活动倒计时 🎉、紧张刺激的验证码倒计时 📱,还是各种需要时间提醒的场景,CountDown 都能像一位贴心的助手一样,为你精准计时,让每一秒都充满仪式感!
📦 引入
通过以下方式来全局注册组件,更多注册方式请参考组件注册。
import { createApp } from'vue'; import { CountDown } from'vant'; const app = createApp(); app.use(CountDown);🎯 代码演示
🔧 基础用法 - 开启你的时间之旅
就像设定一个闹钟一样简单!通过 time 属性设置倒计时的总时长(单位为毫秒),CountDown 就会像一个精准的时钟一样开始为你倒数每一秒。
import { ref } from'vue'; exportdefault { setup() { const time = ref(30 * 60 * 60 * 1000); return { time }; }, };🎨 自定义格式 - 让时间穿上漂亮的外衣
时间也需要美美的展示方式!通过 format 属性,你可以像设计师一样为倒计时定制专属的显示格式,让时间以最优雅的姿态呈现在用户面前。
⚡ 毫秒级渲染 - 追求极致的时间精度
想要更加丝滑的倒计时体验吗?默认情况下,倒计时每秒更新一次,就像心跳一样稳定。但当你开启 millisecond 属性后,它就会变身为一台高精度的计时器,每毫秒都在跳动,给用户带来极致流畅的视觉体验!
🎭 自定义样式 - 释放你的创意天赋
不满足于默认的样式?没问题!通过插槽功能,你可以像艺术家一样自由创作,打造独一无二的倒计时界面。timeData 对象就像你的调色盘,包含了所有时间数据,让你的创意尽情挥洒!
🎮 手动控制 - 成为时间的主宰者
想要完全掌控时间的节奏?通过 ref 获取组件实例,你就拥有了时间魔法的三大法术:start(开始)、pause(暂停)、reset(重置)。就像遥控器一样,让时间在你的指尖起舞!
import { showToast } from'vant'; exportdefault { setup() { const countDown = ref(null); conststart = () => { countDown.value.start(); }; constpause = () => { countDown.value.pause(); }; constreset = () => { countDown.value.reset(); }; constonFinish = () => showToast('倒计时结束'); return { start, pause, reset, onFinish, countDown, }; }, };API
Props
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| time | 倒计时时长,单位毫秒 | *number | string* |
| format | 时间格式 | string | HH:mm:ss |
| auto-start | 是否自动开始倒计时 | boolean | true |
| millisecond | 是否开启毫秒级渲染 | boolean | false |
format 格式
| 格式 | 说明 |
|---|---|
| DD | 天数 |
| HH | 小时 |
| mm | 分钟 |
| ss | 秒数 |
| S | 毫秒(1 位) |
| SS | 毫秒(2 位) |
| SSS | 毫秒(3 位) |
Events
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| finish | 倒计时结束时触发 | - |
| change | 倒计时变化时触发 | currentTime: CurrentTime |
Slots
| 名称 | 说明 | 参数 |
|---|---|---|
| default | 自定义内容 | currentTime: CurrentTime |
CurrentTime 格式
| 名称 | 说明 | 类型 |
|---|---|---|
| total | 剩余总时间(单位毫秒) | number |
| days | 剩余天数 | number |
| hours | 剩余小时 | number |
| minutes | 剩余分钟 | number |
| seconds | 剩余秒数 | number |
| milliseconds | 剩余毫秒 | number |
方法
通过 ref 可以获取到 CountDown 实例并调用实例方法,详见组件实例方法。
| 方法名 | 说明 | 参数 | 返回值 |
|---|---|---|---|
| start | 开始倒计时 | - | - |
| pause | 暂停倒计时 | - | - |
| reset | 重设倒计时,若 auto-start 为 true,重设后会自动开始倒计时 | - | - |
类型定义
组件导出以下类型定义:
importtype { CountDownProps, CountDownInstance, CountDownCurrentTime, } from'vant';CountDownInstance 是组件实例的类型,用法如下:
import { ref } from'vue'; importtype { CountDownInstance } from'vant'; const countDownRef = ref<CountDownInstance>(); countDownRef.value?.start();主题定制
样式变量
组件提供了下列 CSS 变量,可用于自定义样式,使用方法请参考 ConfigProvider 组件。
| 名称 | 默认值 | 描述 |
|---|---|---|
| --van-count-down-text-color | var(--van-text-color) | - |
| --van-count-down-font-size | var(--van-font-size-md) | - |
| --van-count-down-line-height | var(--van-line-height-md) | - |
❓ 常见问题
在 iOS 系统上倒计时不生效?
如果你遇到了在 iOS 上倒计时不生效的问题,请确认在创建 Date 对象时没有使用new Date('2020-01-01')这样的写法,iOS 不支持以中划线分隔的日期格式,正确写法是new Date('2020/01/01')。
对此问题的详细解释:stackoverflow。
🌟 最佳实践
性能优化建议
// 避免频繁的毫秒级渲染,除非必要
<van-count-down
:time="time"
:millisecond="false" // 默认即可,性能更好
format="HH:mm:ss"
/>
// 大量倒计时组件时,使用节流
import { throttle } from 'lodash-es';
const handleChange = throttle((currentTime) => {
console.log('倒计时变化:', currentTime);
}, 100);用户体验优化
// 添加音效提醒
const onFinish = () => {
// 播放提示音
const audio = new Audio('/sounds/countdown-finish.mp3');
audio.play();
// 震动反馈(移动端)
if (navigator.vibrate) {
navigator.vibrate([200, 100, 200]);
}
};
// 视觉反馈
const getCountdownClass = (seconds) => {
if (seconds <= 10) return 'countdown-urgent';
if (seconds <= 30) return 'countdown-warning';
return 'countdown-normal';
};💡 使用技巧
动态倒计时场景
// 服务器时间同步
const syncServerTime = async () => {
const response = await fetch('/api/server-time');
const serverTime = await response.json();
const localTime = Date.now();
const timeDiff = serverTime - localTime;
// 调整倒计时
const adjustedTime = targetTime - timeDiff;
return Math.max(0, adjustedTime);
};
// 网络断线重连后同步
window.addEventListener('online', () => {
syncServerTime().then(time => {
countDownRef.value?.reset();
// 重新设置时间
});
});多语言时间格式
const formatByLocale = (locale) => {
const formats = {
'zh-CN': 'DD天 HH:mm:ss',
'en-US': 'DD days HH:mm:ss',
'ja-JP': 'DD日 HH:mm:ss'
};
return formats[locale] || formats['zh-CN'];
};🔧 常见问题解决
时间精度问题
// Q: 为什么倒计时不准确?
// A: 避免使用不准确的时间计算
// ❌ 错误做法
const endTime = new Date('2024-12-31 23:59:59');
const now = new Date();
const time = endTime - now; // 可能不准确
// ✅ 正确做法
const getAccurateTime = async () => {
const response = await fetch('/api/server-time');
const serverTime = await response.json();
const endTime = new Date('2024-12-31T23:59:59Z').getTime();
return Math.max(0, endTime - serverTime);
};页面切换后倒计时停止
// 使用 Page Visibility API 处理页面切换
let pausedTime = 0;
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
// 页面隐藏时记录时间
pausedTime = Date.now();
} else {
// 页面显示时同步时间
if (pausedTime) {
const elapsed = Date.now() - pausedTime;
// 调整倒计时
syncCountdown(elapsed);
}
}
});内存泄漏预防
// 组件销毁时清理定时器
onUnmounted(() => {
if (countDownRef.value) {
countDownRef.value.pause();
}
});🎨 设计灵感
创意倒计时样式
/* 霓虹灯效果 */
.neon-countdown {
color: #00ffff;
text-shadow:
0 0 5px #00ffff,
0 0 10px #00ffff,
0 0 15px #00ffff;
animation: neon-flicker 2s infinite alternate;
}
/* 翻页效果 */
.flip-countdown {
perspective: 1000px;
}
.flip-countdown .digit {
transform-style: preserve-3d;
transition: transform 0.6s;
}
/* 进度环形倒计时 */
.circular-countdown {
position: relative;
width: 120px;
height: 120px;
}
.circular-countdown svg {
transform: rotate(-90deg);
}
.circular-countdown .progress-ring {
stroke-dasharray: 377; /* 2 * π * 60 */
stroke-dashoffset: 377;
animation: countdown-progress linear;
}主题变体
// 紧急倒计时主题
const urgentTheme = {
'--van-count-down-text-color': '#ff4444',
'--van-count-down-font-size': '24px',
'--van-count-down-font-weight': 'bold'
};
// 优雅倒计时主题
const elegantTheme = {
'--van-count-down-text-color': '#666',
'--van-count-down-font-size': '16px',
'--van-count-down-font-family': 'serif'
};🚀 高级功能扩展
自定义倒计时组件
<template>
<div class="advanced-countdown">
<van-count-down
ref="countDown"
:time="time"
:format="format"
@change="handleChange"
@finish="handleFinish"
>
<template #default="{ currentTime }">
<div class="time-blocks">
<div class="time-block">
<span class="number">{{ currentTime.days }}</span>
<span class="label">天</span>
</div>
<div class="time-block">
<span class="number">{{ currentTime.hours }}</span>
<span class="label">时</span>
</div>
<div class="time-block">
<span class="number">{{ currentTime.minutes }}</span>
<span class="label">分</span>
</div>
<div class="time-block">
<span class="number">{{ currentTime.seconds }}</span>
<span class="label">秒</span>
</div>
</div>
</template>
</van-count-down>
</div>
</template>📚 延伸阅读
技术文档
- Vue 3 响应式原理 - 深入理解响应式
- JavaScript 定时器最佳实践 - 定时器优化
- Web Performance API - 性能监控
设计资源
- Material Design Time - 时间组件设计规范
- Apple HIG Time - iOS 时间设计指南
- Ant Design Time - 企业级时间组件
相关组件
- Progress 进度条 - 进度展示组件
- Circle 环形进度条 - 环形进度展示
- Skeleton 骨架屏 - 加载占位组件
- Loading 加载 - 加载状态组件
- DatePicker 日期选择器 - 日期时间选择
- Calendar 日历 - 日历组件