CircularProgress
This commit is contained in:
parent
9d6086726d
commit
79bd72febb
|
@ -0,0 +1,157 @@
|
|||
<template>
|
||||
<div class="circular-progress-container">
|
||||
<div class="circular-progress" :style="{ width: size + 'px', height: size + 'px' }">
|
||||
<svg class="circular-progress-svg" :width="size" :height="size">
|
||||
<!-- 背景圆环 -->
|
||||
<circle
|
||||
class="circular-progress-bg"
|
||||
:cx="center"
|
||||
:cy="center"
|
||||
:r="radius"
|
||||
:stroke-width="strokeWidth"
|
||||
fill="none"
|
||||
/>
|
||||
<!-- 进度圆环 -->
|
||||
<circle
|
||||
class="circular-progress-fill"
|
||||
:cx="center"
|
||||
:cy="center"
|
||||
:r="radius"
|
||||
:stroke-width="strokeWidth"
|
||||
fill="none"
|
||||
:stroke-dasharray="circumference"
|
||||
:stroke-dashoffset="strokeDashoffset"
|
||||
:style="{ stroke: progressColor }"
|
||||
/>
|
||||
</svg>
|
||||
<!-- 中心文本 -->
|
||||
<div class="circular-progress-text" v-if="showText">
|
||||
<span class="progress-percent">{{ percent }}%</span>
|
||||
<span class="progress-label" v-if="label">{{ label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
|
||||
interface Props {
|
||||
percent: number
|
||||
size?: number
|
||||
strokeWidth?: number
|
||||
showText?: boolean
|
||||
label?: string
|
||||
color?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
size: 60,
|
||||
strokeWidth: 4,
|
||||
showText: true,
|
||||
label: '',
|
||||
color: ''
|
||||
})
|
||||
|
||||
// 计算圆环参数
|
||||
const center = computed(() => props.size / 2)
|
||||
const radius = computed(() => (props.size - props.strokeWidth) / 2)
|
||||
const circumference = computed(() => 2 * Math.PI * radius.value)
|
||||
const strokeDashoffset = computed(() => circumference.value - (props.percent / 100) * circumference.value)
|
||||
|
||||
// 进度颜色
|
||||
const progressColor = computed(() => {
|
||||
if (props.color) return props.color
|
||||
|
||||
if (props.percent >= 80) return '#52c41a'
|
||||
if (props.percent >= 60) return '#1890ff'
|
||||
if (props.percent >= 40) return '#faad14'
|
||||
if (props.percent > 0) return '#ff4d4f'
|
||||
return '#d9d9d9'
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.circular-progress-container {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.circular-progress {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.circular-progress-svg {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.circular-progress-bg {
|
||||
stroke: #f0f2f5;
|
||||
}
|
||||
|
||||
.circular-progress-fill {
|
||||
transition: stroke-dashoffset 0.6s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
stroke-linecap: round;
|
||||
}
|
||||
|
||||
.circular-progress-text {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.progress-percent {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #1d2129;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.progress-label {
|
||||
font-size: 10px;
|
||||
color: #86909c;
|
||||
margin-top: 2px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
// 不同尺寸的样式调整
|
||||
.circular-progress[style*="width: 40px"],
|
||||
.circular-progress[style*="width: 40px;"] {
|
||||
.progress-percent {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.progress-label {
|
||||
font-size: 9px;
|
||||
}
|
||||
}
|
||||
|
||||
.circular-progress[style*="width: 80px"],
|
||||
.circular-progress[style*="width: 80px;"] {
|
||||
.progress-percent {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.progress-label {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
|
||||
.circular-progress[style*="width: 100px"],
|
||||
.circular-progress[style*="width: 100px;"] {
|
||||
.progress-percent {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.progress-label {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue