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';
export default {
setup() {
const time = ref(30 * 60 * 60 * 1000);
return { time };
},
};🎨 自訂格式 - 讓時間穿上漂亮的外衣
時間也需要美美的展示方式!透過 format 屬性,你可以像設計師一樣為倒數計時定製專屬的顯示格式,讓時間以最優雅的姿態呈現在使用者面前。
⚡ 毫秒級渲染 - 追求極致的時間精度
想要更加絲滑的倒數計時體驗嗎?預設情況下,倒數計時每秒更新一次,就像心跳一樣穩定。但當你開啟 millisecond 屬性後,它就會變身為一台高精度的計時器,每毫秒都在跳動,給使用者帶來極致流暢的視覺體驗!
🎭 自訂樣式 - 釋放你的創意天賦
不滿足於預設的樣式?沒問題!透過插槽功能,你可以像藝術家一樣自由創作,打造獨一無二的倒數計時介面。timeData 物件就像你的調色盤,包含了所有時間資料,讓你的創意盡情揮灑!
🎮 手動控制 - 成為時間的主宰者
想要完全掌控時間的節奏?透過 ref 獲取元件實例,你就擁有了時間魔法的三大法術:start(開始)、pause(暫停)、reset(重置)。就像遙控器一樣,讓時間在你的指尖起舞!
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, };
},
};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,重設後會自動開始倒數計時 | - | - |
類型定義
元件匯出以下類型定義:
import type { CountDownProps, CountDownInstance, CountDownCurrentTime, } from'vant';CountDownInstance 是元件實例的類型,用法如下:
import { ref } from'vue';
import type { 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>📚 延伸閱讀
技術文件
設計資源
相關元件
- Progress 進度條 - 顯示操作進度
- Circle 環形進度條 - 環形進度展示
- NoticeBar 通知欄 - 捲動通知