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'; 
export default { 
  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 元件的寬度,預設為 100px
const circleWidth = 100; 
// 最終渲染出來的進度條寬度(px)
const pxWidth = (strokeWidth * circleWidth) / viewBox;

顏色定制

色彩是 Circle 的靈魂所在 🌈!透過 color 屬性,你可以為進度條披上任何你喜歡的顏色外衣,而 layer-color 屬性則負責裝扮底層的軌道。就像為舞台設置燈光一樣,合適的顏色搭配能讓你的進度條在介面中脫穎而出,成為最亮眼的那顆星!

html

漸變色

想要更加炫酷的視覺效果?color 屬性還支援漸變色魔法 ✨!只需傳入一個物件,就能創造出從一種顏色平滑過渡到另一種顏色的絢麗效果,讓你的進度條如彩虹般絢爛多彩!

html
js
import { ref } from'vue'; 
export default { 
  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
import type { 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構建的企業級移動端解決方案