vue+svg圆形进度条组件
vue+svg圆形进度条组件
一、实现思路
使用svg的circle元素画两个圆形,一个圆形控制进度,一个绘制底色
二、ProgressCircle.vue
代码示例:
<template>
<!-- 圆形进度条控件 -->
<div :class="['progress-circle', `p-circle${randomNumber}`]">
<svg :width="diameter" :height="diameter">
<circle
class="progress-background"
:r="radius"
:cy="center"
:cx="center"
:stroke-width="strokeWidth"
:stroke="color.notOccupied"
fill="none"
/>
<circle
class="progress-line"
:r="radius"
:cy="center"
:cx="center"
:stroke-width="strokeWidth"
:stroke="color.occupy"
stroke-linejoin="round"
stroke-linecap="round"
fill="none"
:stroke-dasharray="dashArray"
:stroke-dashoffset="dashOffset"
/>
</svg>
<div class="progress-container">
<slot></slot>
</div>
</div>
</template>
<script>
import { randomString } from '@/utils/index';
export default {
props: {
strokeWidth: { type: Number, default: 10, validator: value => value > 0 }, //线条宽度
color: { type: Object, default: () => ({ occupy: '#1593ff', notOccupied: '#e0e0e0' }) }, //占比颜色
percentage: { type: Number, required: true, validator: value => value >= 0 && value <= 100 }, //百分比1-100
basisState: { type: String, default: 'width', validator: value => ['width', 'height'].includes(value) } // 默认以父元素宽度为直径长
},
data() {
return {
parentSize: 0,
updateTimer: null,
randomNumber: null
};
},
computed: {
// 直径长度
diameter() {
return this.parentSize >= this.strokeWidth ? this.parentSize : this.strokeWidth;
},
// 半径
radius() {
return (this.diameter - this.strokeWidth) / 2; // 减去 stroke-width 的一半,以确保圆环在 SVG 内部完全可见
},
// 圆心
center() {
return this.diameter / 2;
},
// 周长 2πr
circumference() {
return 2 * Math.PI * this.radius;
},
// 虚线样式,间隔为一个周长
dashArray() {
return this.circumference;
},
// 虚线与路径起点之间的偏移量(周长的剩余占比)
dashOffset() {
return this.circumference - (this.circumference * this.percentage) / 100;
}
},
created() {
this.randomNumber = randomString(10); //生成随机字符串作为类名,确保多个组件存在时不会冲突
},
methods: {
updateParentSize() {
this.$nextTick(() => {
this.updateTimer && clearTimeout(this.updateTimer);
this.updateTimer = setTimeout(() => {
const child = document.querySelector(`.p-circle${this.randomNumber}`);
const parent = child.parentNode;
this.parentSize = this.basisState == 'width' ? parent.offsetWidth : parent.offsetHeight; // 圆环大小以父元素宽度或高度作为直径
}, 300);
});
}
},
mounted() {
this.updateParentSize();
window.addEventListener('resize', this.updateParentSize); // 监听窗口大小变化
},
beforeDestroy() {
this.updateTimer && clearTimeout(this.updateTimer);
window.removeEventListener('resize', this.updateParentSize);
}
};
</script>
<style lang="scss" scoped>
.progress-circle {
position: relative;
.progress-container {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
}
.progress-background {
transform: rotate(-90deg);
// 默认情况下,SVG的圆弧是从3点钟方向(即右侧)开始绘制的
// 通过旋转-90度,可以将起始位置调整到12点钟方向(即顶部)
transform-origin: 50% 50%;
}
.progress-line {
transform: rotate(-90deg);
transform-origin: 50% 50%;
}
</style>
三、父组件使用
<template>
<div class="head-progress">
<ProgressCircle :percentage="Number(extraParams.confirmRate || 0)">
<div class="head_cont">
<span class="he_text">开票进度</span>
<span class="he_prec">{{ extraParams.confirmRate || '0.00' }}%</span>
</div>
</ProgressCircle>
</div>
</template>
<script>
export default {
components: {
ProgressCircle: () => import('@/components/svgGraphic/progressCircle.vue')
}
};
</script>
<style lang="scss" scoped>
.head-progress {
width: 100px;
height: 100px;
margin-right: 30px;
.head_cont {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.he_text {
font-size: 14px;
color: #7180b0;
}
.he_prec {
font-weight: 600;
font-size: 16px;
color: #0e1119;
line-height: 28px;
}
}
}
</style>
四、实现效果
原文地址:https://blog.csdn.net/m0_52228571/article/details/143788237
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!