uniapp小程序封装圆环显示比例数据

如下是组件信息
1.顺时针旋转

2.逆时针旋转

bash 复制代码
<template>
	<!-- 圆环组件 -->
	<view class="circle-box" :style="{width: size + 'px', height: size + 'px'}">
		<canvas type="2d" id="ringCanvas" class="canvas" :style="{width: size + 'px', height: size + 'px'}"></canvas>
		<!-- 中间文字:显示原始值 -->
		<view class="num-text" v-if="showText">{{ percent }}%</view>
	</view>
</template>

<script>
	export default {
		props: {
			// 百分比数值
			percent: {
				type: Number,
				default: 50
			},
			// 圆环背景色
			bgColor: {
				type: String,
				default: '#ECECEC'
			},
			// 圆环填充色
			activeColor: {
				type: String,
				default: '#409EFF'
			},
			// 线条宽度
			lineWidth: {
				type: Number,
				default: 6
			},
			// 宽高大小
			size: {
				type: Number,
				default: 150
			},
			// 是否现在中间文字
			showText: {
				type: Boolean,
				default: false
			}
		},
		data() {
			return {
				drawTimer: null
			}
		},
		watch: {
			percent: {
				handler() {
					this.debounceDraw()
				},
				immediate: true
			},
			activeColor() {
				this.debounceDraw()
			},
			lineWidth() {
				this.debounceDraw()
			},
			size() {
				this.debounceDraw()
			},
			bgColor() {
				this.debounceDraw()
			}
		},
		onReady() {
			// 确保 Canvas 节点真实渲染后再绘制
			setTimeout(() => {
				this.drawRing()
			}, 30)
		},
		beforeDestroy() {
			if (this.drawTimer) clearTimeout(this.drawTimer)
		},
		methods: {
			debounceDraw() {
				if (this.drawTimer) clearTimeout(this.drawTimer)
				this.drawTimer = setTimeout(() => {
					this.drawRing()
				}, 10)
			},
			drawRing() {
				const query = uni.createSelectorQuery().in(this)
				query.select('#ringCanvas')
					.fields({
						node: true,
						size: true
					})
					.exec(res => {
						if (!res || !res[0] || !res[0].node) return

						const canvas = res[0].node
						const ctx = canvas.getContext('2d')
						const dpr = uni.getSystemInfoSync().pixelRatio || 2

						canvas.width = this.size * dpr
						canvas.height = this.size * dpr
						ctx.scale(dpr, dpr)

						const cx = this.size / 2
						const cy = this.size / 2
						const r = cx - this.lineWidth / 2

						ctx.clearRect(0, 0, this.size, this.size)

						// 1. 绘制背景圆环
						ctx.beginPath()
						ctx.arc(cx, cy, r, 0, 2 * Math.PI)
						ctx.lineWidth = this.lineWidth
						ctx.strokeStyle = this.bgColor
						ctx.stroke()

						// 真实绘制百分比
						let realPercent = Math.max(0, Math.min(100, this.percent))
						let drawPercent = realPercent

						// 只有100%才闭合,非满圈保留缺口
						const isFull = realPercent >= 100
						if (!isFull) {
							drawPercent = Math.min(realPercent, 95)
						}

						// ==============================================
						// 顺时针绘制(从顶部开始)
						// ==============================================
						const startRad = -Math.PI / 2 // 顶部起点
						// const endRad = startRad + (drawPercent / 100) * 2 * Math.PI  //顺时针
						const endRad = startRad - (drawPercent / 100) * 2 * Math.PI //逆时针

						ctx.beginPath()
						ctx.arc(cx, cy, r, startRad, endRad, true) // false = 顺时针  true = 逆时针
						ctx.strokeStyle = this.activeColor
						ctx.lineWidth = this.lineWidth
						ctx.lineCap = 'round'
						ctx.stroke()
					})
			}
		}
	}
</script>

<style scoped>
	.circle-box {
		position: relative;
		margin: 0 auto;
	}

	.canvas {
		display: block;
		width: 100%;
		height: 100%;
	}

	.num-text {
		position: absolute;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%);
		font-size: 28rpx;
		color: #333;
		font-weight: bold;
		pointer-events: none;
	}
</style>

顺时针/逆时针的代码差别

bash 复制代码
const endRad = startRad + (drawPercent / 100) * 2 * Math.PI  //顺时针
const endRad = startRad - (drawPercent / 100) * 2 * Math.PI   //逆时针


ctx.arc(cx, cy, r, startRad, endRad, true) // false = 顺时针  true = 逆时针
相关推荐
通玄3 小时前
Jetpack Compose 入门系列(十):Paging 3 分页加载
android
hunterandroid3 小时前
DataStore 工程化实践:迁移、并发更新与异常恢复
android·前端
程序员-珍5 小时前
报错下载android sdk失败
android·java
小码哥0687 小时前
从三甲综合医院到连锁诊所:医院管理小程序的场景化突围逻辑(陪诊系统-陪诊APP-陪诊小程序)
小程序·医院管理系统·陪诊小程序·陪诊系统·陪诊app
齊家治國平天下7 小时前
AAOS 电源管理深度解析:休眠/唤醒/功耗优化
android·车载系统·aaos·aosp·电源管理·休眠唤醒·carpowermanager
qq3621967057 小时前
安卓大版本升级后APK不兼容怎么办?2026跨版本更新指南
android
Xzaveir7 小时前
企业号码展示不可观测怎么办:状态机、拨测事件与异常回放
android·人工智能
2501_916007477 小时前
iOS和macOS应用程序性能分析和优化工具使用综合指南
android·macos·ios·小程序·uni-app·iphone·webview
黄林晴8 小时前
Nearby Connections 重大变更:不再自动开启 Wi-Fi / 蓝牙,适配指南
android
恋猫de小郭8 小时前
Flutter 全新真 3D 实现,用 flutter_scene 能开发一个「我的世界」
android·前端·flutter