Skip to content

CountDown 倒计时 - Vant 4

⏰ CountDown 倒计时

⏳ 介绍

时间就像流水一样珍贵,CountDown 倒计时组件就是你的专属时间管家!⏰ 它能够精确到毫秒地展示倒计时,就像一个永不疲倦的时间守护者。

无论是激动人心的活动倒计时 🎉、紧张刺激的验证码倒计时 📱,还是各种需要时间提醒的场景,CountDown 都能像一位贴心的助手一样,为你精准计时,让每一秒都充满仪式感!

📦 引入

通过以下方式来全局注册组件,更多注册方式请参考组件注册

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

🎯 代码演示

🔧 基础用法 - 开启你的时间之旅

就像设定一个闹钟一样简单!通过 time 属性设置倒计时的总时长(单位为毫秒),CountDown 就会像一个精准的时钟一样开始为你倒数每一秒。

html
js
import { ref } from'vue'; exportdefault { setup() { const time = ref(30 * 60 * 60 * 1000); return { time }; }, };

🎨 自定义格式 - 让时间穿上漂亮的外衣

时间也需要美美的展示方式!通过 format 属性,你可以像设计师一样为倒计时定制专属的显示格式,让时间以最优雅的姿态呈现在用户面前。

html

⚡ 毫秒级渲染 - 追求极致的时间精度

想要更加丝滑的倒计时体验吗?默认情况下,倒计时每秒更新一次,就像心跳一样稳定。但当你开启 millisecond 属性后,它就会变身为一台高精度的计时器,每毫秒都在跳动,给用户带来极致流畅的视觉体验!

html

🎭 自定义样式 - 释放你的创意天赋

不满足于默认的样式?没问题!通过插槽功能,你可以像艺术家一样自由创作,打造独一无二的倒计时界面。timeData 对象就像你的调色盘,包含了所有时间数据,让你的创意尽情挥洒!

html

🎮 手动控制 - 成为时间的主宰者

想要完全掌控时间的节奏?通过 ref 获取组件实例,你就拥有了时间魔法的三大法术:start(开始)、pause(暂停)、reset(重置)。就像遥控器一样,让时间在你的指尖起舞!

html
js
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倒计时时长,单位毫秒*numberstring*
format时间格式stringHH:mm:ss
auto-start是否自动开始倒计时booleantrue
millisecond是否开启毫秒级渲染booleanfalse

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-starttrue,重设后会自动开始倒计时--

类型定义

组件导出以下类型定义:

ts
importtype { CountDownProps, CountDownInstance, CountDownCurrentTime, } from'vant';

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

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

主题定制

样式变量

组件提供了下列 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)-

❓ 常见问题

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

如果你遇到了在 iOS 上倒计时不生效的问题,请确认在创建 Date 对象时没有使用new Date('2020-01-01')这样的写法,iOS 不支持以中划线分隔的日期格式,正确写法是new Date('2020/01/01')

对此问题的详细解释:stackoverflow

🌟 最佳实践

性能优化建议

javascript
// 避免频繁的毫秒级渲染,除非必要
<van-count-down 
  :time="time" 
  :millisecond="false"  // 默认即可,性能更好
  format="HH:mm:ss" 
/>

// 大量倒计时组件时,使用节流
import { throttle } from 'lodash-es';

const handleChange = throttle((currentTime) => {
  console.log('倒计时变化:', currentTime);
}, 100);

用户体验优化

javascript
// 添加音效提醒
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';
};

💡 使用技巧

动态倒计时场景

javascript
// 服务器时间同步
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();
    // 重新设置时间
  });
});

多语言时间格式

javascript
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'];
};

🔧 常见问题解决

时间精度问题

javascript
// 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);
};

页面切换后倒计时停止

javascript
// 使用 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);
    }
  }
});

内存泄漏预防

javascript
// 组件销毁时清理定时器
onUnmounted(() => {
  if (countDownRef.value) {
    countDownRef.value.pause();
  }
});

🎨 设计灵感

创意倒计时样式

css
/* 霓虹灯效果 */
.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;
}

主题变体

javascript
// 紧急倒计时主题
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'
};

🚀 高级功能扩展

自定义倒计时组件

vue
<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>

📚 延伸阅读

技术文档

设计资源

相关组件

基於Vant構建的企業級移動端解決方案