Circle 环形进度条 - Vant 4
Circle 环形进度条
⭕ 介绍
Circle 环形进度条就像一个优雅的时钟表盘,以圆润流畅的弧线诉说着进度的故事 🕐。它不仅仅是一个简单的进度指示器,更像是一位贴心的向导,用丝滑的动画和渐变的色彩,将枯燥的数字转化为赏心悦目的视觉盛宴。无论是展示文件下载进度、任务完成度,还是技能熟练度,Circle 都能以其独特的圆环魅力,让用户在等待中也能感受到美的享受 ✨。
📦 引入
通过以下方式来全局注册组件,更多注册方式请参考组件注册。
import { createApp } from'vue'; import { Circle } from'vant'; const app = createApp(); app.use(Circle);🎯 代码演示
基础用法
Circle 的魅力在于它的智能动画系统 🎬!rate 属性就像是给进度条设定的目标,而 v-model:current-rate 则是实时追踪动画进展的小助手。当你改变 rate 值时,Circle 会像一位优雅的舞者,以 speed 设定的节拍,从当前位置缓缓舞向目标位置,每一帧都充满了流畅的美感,让等待变成一种享受!
import { ref, computed } from'vue'; exportdefault { setup() { const currentRate = ref(0); const text = computed(() => currentRate.value.toFixed(0) + '%'); return { text, currentRate, }; }, };宽度定制
想要让你的进度条更有个性?stroke-width 属性就是你的魔法画笔 🎨!它控制着圆环的粗细程度,就像调节画笔的笔触一样。无论你喜欢纤细优雅的线条,还是粗犷有力的笔触,都能通过这个属性轻松实现。默认值 40 已经很完美,但你完全可以根据设计需求自由调节!
stroke-width 的单位不是 px,如果你想知道 stroke-width 与 px 的换算关系,可以通过如下公式计算:
// SVG 的 viewBox 大小const viewBox = 1000 + strokeWidth; // Circle 组件的宽度,默认为 100pxconst circleWidth = 100; // 最终渲染出来的进度条宽度(px)const pxWidth = (strokeWidth * circleWidth) / viewBox;颜色定制
色彩是 Circle 的灵魂所在 🌈!通过 color 属性,你可以为进度条披上任何你喜欢的颜色外衣,而 layer-color 属性则负责装扮底层的轨道。就像为舞台设置灯光一样,合适的颜色搭配能让你的进度条在界面中脱颖而出,成为最亮眼的那颗星!
渐变色
想要更加炫酷的视觉效果?color 属性还支持渐变色魔法 ✨!只需传入一个对象,就能创造出从一种颜色平滑过渡到另一种颜色的绚丽效果,让你的进度条如彩虹般绚烂多彩!
import { ref } from'vue'; exportdefault { setup() { const currentRate = ref(0); const gradientColor = { '0%': '#3fecff', '100%': '#6149f6', }; return { currentRate, gradientColor, }; }, };逆时针方向
有时候,反向的美也别有一番风味 🔄!将 clockwise 设置为 false,Circle 就会像时光倒流一样,以逆时针的方向优雅地展示进度。这种独特的动画方向能为你的应用增添一丝神秘感和创意感!
大小定制
大小由你掌控!通过 size 属性,你可以随心所欲地调整 Circle 的尺寸 📏。无论是精致小巧的迷你版,还是醒目大气的巨无霸版,都能完美适配你的界面设计需求!
起始位置
谁说进度条一定要从顶部开始?Circle 给你更多选择的自由 🧭!通过 start-position 属性,你可以让进度从顶部、左侧、右侧或底部任意位置开始,就像指南针一样,指向你想要的任何方向!
API
Props
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| v-model:current-rate | 当前进度 | number | - |
| rate | 目标进度 | *number | string* |
| size | 圆环直径,默认单位为 px | *number | string* |
| color | 进度条颜色,传入对象格式可以定义渐变色 | *string | object* |
| 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 | 进度起始位置,可选值为 left、right、bottom | CircleStartPosition | top |
Slots
| 名称 | 说明 |
|---|---|
| default | 自定义文字内容 |
类型定义
组件导出以下类型定义:
importtype { CircleProps, CircleStartPosition } from'vant';主题定制
样式变量
组件提供了下列 CSS 变量,可用于自定义样式,使用方法请参考 ConfigProvider 组件。
| 名称 | 默认值 | 描述 |
|---|---|---|
| --van-circle-size | 100px | - |
| --van-circle-color | var(--van-primary-color) | - |
| --van-circle-layer-color | var(--van-white) | - |
| --van-circle-text-color | var(--van-text-color) | - |
| --van-circle-text-font-weight | var(--van-font-bold) | - |
| --van-circle-text-font-size | var(--van-font-size-md) | - |
| --van-circle-text-line-height | var(--van-line-height-md) | - |
最佳实践
进度展示原则
设计环形进度条时,应该遵循以下原则 🎯:
<!-- ✅ 推荐:清晰的进度信息展示 -->
<van-circle
v-model:current-rate="currentRate"
:rate="targetRate"
:speed="100"
:text="progressText"
color="#1989fa"
/>
<!-- ❌ 避免:过快的动画速度影响用户体验 -->
<van-circle
:rate="100"
:speed="1000"
text="瞬间完成"
/>动画速度控制
合理的动画速度能提升用户体验 ⚡:
// ✅ 推荐:根据进度差值调整动画速度
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)
);文本内容设计
<!-- 多样化的文本展示 -->
<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>性能优化小贴士
动画性能优化
优化环形进度条的动画性能 🚀:
// ✅ 推荐:使用 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();
});内存管理
// 组件卸载时清理定时器
onUnmounted(() => {
if (animationTimer) {
clearInterval(animationTimer);
}
});设计建议
视觉设计
- 尺寸选择:根据内容重要性选择合适尺寸 📐
- 颜色搭配:使用品牌色或语义化颜色 🎨
- 对比度:确保进度条与背景有足够对比度 👁️
- 动画流畅:保持动画的连贯性和自然感 🌊
交互体验
- 即时反馈:进度变化应有即时的视觉反馈 ⚡
- 状态清晰:不同状态应有明确的视觉区分 🚦
- 信息完整:提供必要的进度信息和状态说明 📊
常见问题解决
Q: 如何实现分段式进度条?
<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: 如何实现多个进度条的同步动画?
<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: 如何实现进度条的暂停和恢复?
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 {
// 恢复动画逻辑
}
});高级用法示例
仪表盘样式进度条
<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>技能熟练度展示
<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>相关组件
- Progress 进度条 - 线性进度展示
- Loading 加载 - 加载状态指示
- Skeleton 骨架屏 - 内容加载占位
- Steps 步骤条 - 步骤流程展示