circle-progress组件封装完毕,圆型进度条

This commit is contained in:
WindowBird 2025-08-30 17:44:43 +08:00
parent 80f3004428
commit 155b2bb399
3 changed files with 157 additions and 193 deletions

View File

@ -1,97 +0,0 @@
<template>
<view class="circle-progress">
<view class="circle-progress__content">
<text class="circle-progress__text">{{ percentage }}%</text>
</view>
</view>
</template>
<script>
export default {
name: "CircleProgress",
props: {
// 0-100
percentage: {
type: Number,
default: 0,
validator: (value) => value >= 0 && value <= 100,
},
//
color: {
type: String,
default: "#42b983", // 绿
},
//
backgroundColor: {
type: String,
default: "#c8c8c8", //
},
//
size: {
type: Number,
default: 100,
},
//
borderWidth: {
type: Number,
default: 5,
},
},
computed: {
progressStyle() {
const degrees = this.percentage * 3.6; //
const style = {
width: `${this.size}px`,
height: `${this.size}px`,
borderWidth: `${this.borderWidth}px`,
borderColor: this.backgroundColor,
};
//
if (this.percentage <= 50) {
style.background = `conic-gradient(
${this.color} 0deg ${degrees}deg,
${this.backgroundColor} ${degrees}deg 360deg
)`;
} else {
style.background = `conic-gradient(
${this.color} 0deg 180deg,
${this.backgroundColor} 180deg 360deg
)`;
}
return style;
},
textStyle() {
return {
fontSize: `${this.size * 0.2}px`,
};
},
},
};
</script>
<style lang="scss" scoped>
.circle-progress {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
&__content {
position: relative;
border-radius: 50%;
mask: radial-gradient(transparent 60%, black 61%);
}
&__text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-weight: bold;
color: #333;
z-index: 2;
}
}
</style>

View File

@ -0,0 +1,136 @@
<!--@example-->
<!--<circle-progress-->
<!-- :canvas-size="120"-->
<!-- :progress="80"-->
<!-- content="学习进度"-->
<!-- progress-color="#42b983"-->
<!--&gt;</circle-progress>-->
<template>
<!-- 圆形进度条 -->
<view
:style="{ width: canvasSize + 'px', height: canvasSize + 'px' }"
class="progress-container"
>
<canvas
:style="{ width: canvasSize + 'px', height: canvasSize + 'px' }"
canvas-id="progressCanvas"
class="progress-canvas"
></canvas>
<view class="progress-text">
<text class="percent">{{ progress }}%</text>
<text class="label">{{ content }}</text>
</view>
</view>
</template>
<script>
export default {
name: "circle-progress",
props: {
progress: {
type: Number,
default: 80,
},
canvasSize: {
type: Number,
default: 80,
},
strokeWidth: {
type: Number,
default: 12,
},
bgColor: {
type: String,
default: "#f0f0f0",
},
progressColor: {
type: String,
default: "#007AFF",
},
textColor: {
type: String,
default: "#333",
},
content: {
type: String,
default: "进度",
},
},
mounted() {
this.drawProgress();
},
watch: {
progress() {
this.drawProgress();
},
progressColor() {
this.drawProgress();
},
},
methods: {
//
drawProgress() {
const { progress, canvasSize, strokeWidth, bgColor, progressColor } =
this;
const ctx = uni.createCanvasContext("progressCanvas", this);
const center = canvasSize / 2;
const radius = center - strokeWidth / 2;
//
ctx.clearRect(0, 0, canvasSize, canvasSize);
//
ctx.beginPath();
ctx.arc(center, center, radius, 0, 2 * Math.PI);
ctx.setStrokeStyle(bgColor);
ctx.setLineWidth(strokeWidth);
ctx.stroke();
//
const startAngle = -Math.PI / 2; //
const endAngle = startAngle + (progress / 100) * 2 * Math.PI;
ctx.beginPath();
ctx.arc(center, center, radius, startAngle, endAngle);
ctx.setStrokeStyle(progressColor);
ctx.setLineWidth(strokeWidth);
ctx.setLineCap("round");
ctx.stroke();
ctx.draw();
},
},
};
</script>
<style scoped>
.progress-container {
position: relative;
}
.progress-canvas {
border-radius: 50%;
box-shadow: 0 8rpx 25rpx rgba(0, 0, 0, 0.1);
}
.progress-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
}
.percent {
font-size: 36rpx;
font-weight: bold;
color: #333;
display: block;
}
.label {
font-size: 24rpx;
color: #666;
display: block;
margin-top: 10rpx;
}
</style>

View File

@ -1,118 +1,43 @@
<template>
<view class="page">
<!-- 圆形进度条 -->
<view class="progress-container">
<canvas
:style="{ width: canvasSize + 'px', height: canvasSize + 'px' }"
canvas-id="progressCanvas"
class="progress-canvas"
></canvas>
<view class="progress-text">
<text class="percent">{{ progress }}%</text>
<text class="label">{{ content }}</text>
</view>
</view>
<circle-progress
:canvas-size="120"
:progress="80"
content="学习进度"
progress-color="#42b983"
></circle-progress>
</view>
</template>
<script>
import CommonEnum from "../../enum/common";
export default {
data() {
return {
progress: 80, // 0-100
canvasSize: 80, //
strokeWidth: 12, // 线
bgColor: "#f0f0f0", //
progressColor: "#007AFF", //
textColor: "#333", //
content: "", //,
CommonEnum,
};
},
mounted() {
this.drawProgress();
},
watch: {
progress() {
this.drawProgress();
},
progressColor() {
this.drawProgress();
},
onLoad() {
//
},
methods: {
//
drawProgress() {
const { progress, canvasSize, strokeWidth, bgColor, progressColor } =
this;
const ctx = uni.createCanvasContext("progressCanvas", this);
const center = canvasSize / 2;
const radius = center - strokeWidth / 2;
//
ctx.clearRect(0, 0, canvasSize, canvasSize);
//
ctx.beginPath();
ctx.arc(center, center, radius, 0, 2 * Math.PI);
ctx.setStrokeStyle(bgColor);
ctx.setLineWidth(strokeWidth);
ctx.stroke();
//
const startAngle = -Math.PI / 2; //
const endAngle = startAngle + (progress / 100) * 2 * Math.PI;
ctx.beginPath();
ctx.arc(center, center, radius, startAngle, endAngle);
ctx.setStrokeStyle(progressColor);
ctx.setLineWidth(strokeWidth);
ctx.setLineCap("round");
ctx.stroke();
ctx.draw();
},
//
},
};
</script>
<style scoped>
<style lang="scss" scoped>
.page {
background: #ffffff;
}
.header {
width: 100%;
//min-height: 100vh;//
display: flex;
align-items: flex-start;
flex-direction: column;
align-items: center;
padding: 40rpx;
min-height: 100vh;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
}
.progress-container {
position: relative;
margin: 40rpx 0;
}
.progress-canvas {
border-radius: 50%;
box-shadow: 0 8rpx 25rpx rgba(0, 0, 0, 0.1);
}
.progress-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
}
.percent {
font-size: 36rpx;
font-weight: bold;
color: #333;
display: block;
}
.label {
font-size: 24rpx;
color: #666;
display: block;
margin-top: 10rpx;
padding: 0 15rpx 40rpx;
}
</style>