Skip to content

Circle 环形进度条 - Vant 4

Circle 环形进度条

⭕ 介绍

Circle 环形进度条就像一个优雅的时钟表盘,以圆润流畅的弧线诉说着进度的故事 🕐。它不仅仅是一个简单的进度指示器,更像是一位贴心的向导,用丝滑的动画和渐变的色彩,将枯燥的数字转化为赏心悦目的视觉盛宴。无论是展示文件下载进度、任务完成度,还是技能熟练度,Circle 都能以其独特的圆环魅力,让用户在等待中也能感受到美的享受 ✨。

📦 引入

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

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

🎯 代码演示

基础用法

Circle 的魅力在于它的智能动画系统 🎬!rate 属性就像是给进度条设定的目标,而 v-model:current-rate 则是实时追踪动画进展的小助手。当你改变 rate 值时,Circle 会像一位优雅的舞者,以 speed 设定的节拍,从当前位置缓缓舞向目标位置,每一帧都充满了流畅的美感,让等待变成一种享受!

html
js
import { ref, computed } from'vue'; exportdefault { setup() { const currentRate = ref(0); const text = computed(() => currentRate.value.toFixed(0) + '%'); return { text, currentRate, }; }, };

宽度定制

想要让你的进度条更有个性?stroke-width 属性就是你的魔法画笔 🎨!它控制着圆环的粗细程度,就像调节画笔的笔触一样。无论你喜欢纤细优雅的线条,还是粗犷有力的笔触,都能通过这个属性轻松实现。默认值 40 已经很完美,但你完全可以根据设计需求自由调节!

html

stroke-width 的单位不是 px,如果你想知道 stroke-widthpx 的换算关系,可以通过如下公式计算:

js
// SVG 的 viewBox 大小const viewBox = 1000 + strokeWidth; // Circle 组件的宽度,默认为 100pxconst circleWidth = 100; // 最终渲染出来的进度条宽度(px)const pxWidth = (strokeWidth * circleWidth) / viewBox;

颜色定制

色彩是 Circle 的灵魂所在 🌈!通过 color 属性,你可以为进度条披上任何你喜欢的颜色外衣,而 layer-color 属性则负责装扮底层的轨道。就像为舞台设置灯光一样,合适的颜色搭配能让你的进度条在界面中脱颖而出,成为最亮眼的那颗星!

html

渐变色

想要更加炫酷的视觉效果?color 属性还支持渐变色魔法 ✨!只需传入一个对象,就能创造出从一种颜色平滑过渡到另一种颜色的绚丽效果,让你的进度条如彩虹般绚烂多彩!

html
js
import { ref } from'vue'; exportdefault { setup() { const currentRate = ref(0); const gradientColor = { '0%': '#3fecff', '100%': '#6149f6', }; return { currentRate, gradientColor, }; }, };

逆时针方向

有时候,反向的美也别有一番风味 🔄!将 clockwise 设置为 false,Circle 就会像时光倒流一样,以逆时针的方向优雅地展示进度。这种独特的动画方向能为你的应用增添一丝神秘感和创意感!

html

大小定制

大小由你掌控!通过 size 属性,你可以随心所欲地调整 Circle 的尺寸 📏。无论是精致小巧的迷你版,还是醒目大气的巨无霸版,都能完美适配你的界面设计需求!

html

起始位置

谁说进度条一定要从顶部开始?Circle 给你更多选择的自由 🧭!通过 start-position 属性,你可以让进度从顶部、左侧、右侧或底部任意位置开始,就像指南针一样,指向你想要的任何方向!

html

API

Props

参数说明类型默认值
v-model:current-rate当前进度number-
rate目标进度*numberstring*
size圆环直径,默认单位为 px*numberstring*
color进度条颜色,传入对象格式可以定义渐变色*stringobject*

| layer-color | 轨道颜色 | string | white | | fill | 填充颜色 | string | none | | speed | 动画速度(单位为 rate/s) | number | string | 0 | | text | 文字 | string | - | | stroke-width | 进度条宽度 | number | string | 40 | | stroke-linecap | 进度条端点的形状,可选值为 square``butt | string | round | | clockwise | 是否顺时针增加 | boolean | true | | start-position | 进度起始位置,可选值为 leftrightbottom | CircleStartPosition | top |

Slots

名称说明
default自定义文字内容

类型定义

组件导出以下类型定义:

ts
importtype { CircleProps, CircleStartPosition } from'vant';

主题定制

样式变量

组件提供了下列 CSS 变量,可用于自定义样式,使用方法请参考 ConfigProvider 组件

名称默认值描述
--van-circle-size100px-
--van-circle-colorvar(--van-primary-color)-
--van-circle-layer-colorvar(--van-white)-
--van-circle-text-colorvar(--van-text-color)-
--van-circle-text-font-weightvar(--van-font-bold)-
--van-circle-text-font-sizevar(--van-font-size-md)-
--van-circle-text-line-heightvar(--van-line-height-md)-

最佳实践

进度展示原则

设计环形进度条时,应该遵循以下原则 🎯:

html
<!-- ✅ 推荐:清晰的进度信息展示 -->
<van-circle 
  v-model:current-rate="currentRate" 
  :rate="targetRate"
  :speed="100"
  :text="progressText"
  color="#1989fa"
/>

<!-- ❌ 避免:过快的动画速度影响用户体验 -->
<van-circle 
  :rate="100" 
  :speed="1000"
  text="瞬间完成"
/>

动画速度控制

合理的动画速度能提升用户体验 ⚡:

javascript
// ✅ 推荐:根据进度差值调整动画速度
const calculateSpeed = (currentRate, targetRate) => {
  const diff = Math.abs(targetRate - currentRate);
  if (diff <= 10) return 50;  // 小幅变化,慢速动画
  if (diff <= 50) return 100; // 中等变化,中速动画
  return 200; // 大幅变化,快速动画
};

// 动态调整动画速度
const animationSpeed = computed(() => 
  calculateSpeed(currentRate.value, targetRate.value)
);

文本内容设计

html
<!-- 多样化的文本展示 -->
<van-circle v-model:current-rate="currentRate" :rate="80">
  <template #default>
    <div class="circle-text">
      <div class="percentage">{{ Math.round(currentRate) }}%</div>
      <div class="label">已完成</div>
    </div>
  </template>
</van-circle>

<style>
.circle-text {
  text-align: center;
}
.percentage {
  font-size: 18px;
  font-weight: bold;
  color: #1989fa;
}
.label {
  font-size: 12px;
  color: #969799;
  margin-top: 4px;
}
</style>

性能优化小贴士

动画性能优化

优化环形进度条的动画性能 🚀:

javascript
// ✅ 推荐:使用 requestAnimationFrame 优化动画
const smoothProgress = ref(0);
const targetProgress = ref(0);

const animateProgress = () => {
  const diff = targetProgress.value - smoothProgress.value;
  if (Math.abs(diff) < 0.1) {
    smoothProgress.value = targetProgress.value;
    return;
  }
  
  smoothProgress.value += diff * 0.1;
  requestAnimationFrame(animateProgress);
};

// 监听目标进度变化
watch(targetProgress, () => {
  animateProgress();
});

内存管理

javascript
// 组件卸载时清理定时器
onUnmounted(() => {
  if (animationTimer) {
    clearInterval(animationTimer);
  }
});

设计建议

视觉设计

  • 尺寸选择:根据内容重要性选择合适尺寸 📐
  • 颜色搭配:使用品牌色或语义化颜色 🎨
  • 对比度:确保进度条与背景有足够对比度 👁️
  • 动画流畅:保持动画的连贯性和自然感 🌊

交互体验

  • 即时反馈:进度变化应有即时的视觉反馈 ⚡
  • 状态清晰:不同状态应有明确的视觉区分 🚦
  • 信息完整:提供必要的进度信息和状态说明 📊

常见问题解决

Q: 如何实现分段式进度条?

html
<van-circle 
  v-model:current-rate="currentRate" 
  :rate="segmentRate"
  :color="segmentColor"
  :text="segmentText"
/>

<script>
const segments = [
  { rate: 25, color: '#ff4444', text: '初级' },
  { rate: 50, color: '#ffaa00', text: '中级' },
  { rate: 75, color: '#00aa00', text: '高级' },
  { rate: 100, color: '#0066ff', text: '专家' }
];

const currentSegment = computed(() => 
  segments.find(seg => currentRate.value <= seg.rate) || segments[segments.length - 1]
);

const segmentRate = computed(() => currentSegment.value.rate);
const segmentColor = computed(() => currentSegment.value.color);
const segmentText = computed(() => currentSegment.value.text);
</script>

Q: 如何实现多个进度条的同步动画?

html
<div class="progress-group">
  <van-circle 
    v-for="(item, index) in progressItems" 
    :key="index"
    v-model:current-rate="item.currentRate"
    :rate="item.targetRate"
    :speed="animationSpeed"
    :color="item.color"
    :text="item.text"
  />
</div>

<script>
const startSyncAnimation = () => {
  progressItems.forEach((item, index) => {
    setTimeout(() => {
      item.targetRate = item.finalRate;
    }, index * 200); // 错开动画时间
  });
};
</script>

Q: 如何实现进度条的暂停和恢复?

javascript
const isPaused = ref(false);
const pausedRate = ref(0);

const pauseProgress = () => {
  isPaused.value = true;
  pausedRate.value = currentRate.value;
};

const resumeProgress = () => {
  isPaused.value = false;
  currentRate.value = pausedRate.value;
};

// 监听暂停状态
watch(isPaused, (paused) => {
  if (paused) {
    // 暂停动画逻辑
  } else {
    // 恢复动画逻辑
  }
});

高级用法示例

仪表盘样式进度条

html
<template>
  <div class="dashboard-circle">
    <van-circle 
      v-model:current-rate="currentRate"
      :rate="targetRate"
      :size="200"
      :stroke-width="20"
      :color="dashboardColor"
      layer-color="#f0f0f0"
      start-position="bottom"
    >
      <div class="dashboard-content">
        <div class="value">{{ Math.round(currentRate) }}</div>
        <div class="unit">km/h</div>
        <div class="label">当前速度</div>
      </div>
    </van-circle>
  </div>
</template>

<style>
.dashboard-content {
  text-align: center;
}
.value {
  font-size: 32px;
  font-weight: bold;
  color: #333;
}
.unit {
  font-size: 14px;
  color: #666;
  margin-top: 4px;
}
.label {
  font-size: 12px;
  color: #999;
  margin-top: 8px;
}
</style>

技能熟练度展示

html
<template>
  <div class="skill-progress">
    <van-circle 
      v-for="skill in skills" 
      :key="skill.name"
      v-model:current-rate="skill.currentRate"
      :rate="skill.level"
      :size="80"
      :color="skill.color"
      :text="skill.name"
      class="skill-item"
    />
  </div>
</template>

<script>
const skills = ref([
  { name: 'Vue', level: 90, currentRate: 0, color: '#4fc08d' },
  { name: 'React', level: 75, currentRate: 0, color: '#61dafb' },
  { name: 'Angular', level: 60, currentRate: 0, color: '#dd0031' }
]);
</script>

相关组件

延伸阅读

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