hookehuyr

feat(组件): 添加动态字体大小调整功能

为积分显示组件添加根据数字长度自动调整字体大小的功能,确保长数字的可读性
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
4 <view class="center-circle"> 4 <view class="center-circle">
5 <view class="total-points" @tap="handleGoToRewards"> 5 <view class="total-points" @tap="handleGoToRewards">
6 <text v-if="!isOwner" class="family-points-label">家庭总积分</text> 6 <text v-if="!isOwner" class="family-points-label">家庭总积分</text>
7 - <text class="points-number">{{ animatedTotalPoints }}分</text> 7 + <text class="points-number" :style="{ fontSize: dynamicFontSize }">{{ animatedTotalPoints }}分</text>
8 <text v-if="isOwner" class="points-label">去兑换</text> 8 <text v-if="isOwner" class="points-label">去兑换</text>
9 </view> 9 </view>
10 </view> 10 </view>
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
35 </template> 35 </template>
36 36
37 <script setup> 37 <script setup>
38 -import { ref, onMounted, defineProps, defineExpose, defineEmits, watch } from 'vue' 38 +import { ref, onMounted, defineProps, defineExpose, defineEmits, watch, computed } from 'vue'
39 import Taro, { useDidShow } from '@tarojs/taro' 39 import Taro, { useDidShow } from '@tarojs/taro'
40 import { collectPointAPI } from '@/api/points' 40 import { collectPointAPI } from '@/api/points'
41 41
...@@ -68,6 +68,25 @@ const animatedTotalPoints = ref(props.totalPoints) // 动画中的总积分 ...@@ -68,6 +68,25 @@ const animatedTotalPoints = ref(props.totalPoints) // 动画中的总积分
68 const floatingItems = ref([]) // 漂浮的积分项 68 const floatingItems = ref([]) // 漂浮的积分项
69 const isCollecting = ref(false) // 是否正在收集,防止重复触发 69 const isCollecting = ref(false) // 是否正在收集,防止重复触发
70 70
71 +/**
72 + * 根据数值长度动态计算字体大小
73 + */
74 +const dynamicFontSize = computed(() => {
75 + const pointsStr = animatedTotalPoints.value + '分'
76 + const length = pointsStr.length
77 +
78 + // 基础字体大小36rpx,超过6位数开始缩小
79 + if (length <= 6) {
80 + return '36rpx'
81 + } else if (length <= 8) {
82 + return '32rpx'
83 + } else if (length <= 10) {
84 + return '28rpx'
85 + } else {
86 + return '24rpx'
87 + }
88 +})
89 +
71 // source_type 中英文映射 90 // source_type 中英文映射
72 const sourceTypeMap = { 91 const sourceTypeMap = {
73 'WALKING': '步数积分', 92 'WALKING': '步数积分',
...@@ -111,20 +130,20 @@ const generatePointsData = () => { ...@@ -111,20 +130,20 @@ const generatePointsData = () => {
111 // 计算项目大小和半径 130 // 计算项目大小和半径
112 const sizeRatio = item.points / maxValue; 131 const sizeRatio = item.points / maxValue;
113 const size = baseSize + (sizeRatio * 40); // rpx 132 const size = baseSize + (sizeRatio * 40); // rpx
114 - 133 +
115 // 优化半径计算,确保在不同屏幕尺寸下都能正确计算边界 134 // 优化半径计算,确保在不同屏幕尺寸下都能正确计算边界
116 // 将rpx转换为百分比,考虑屏幕宽度和高度的比例 135 // 将rpx转换为百分比,考虑屏幕宽度和高度的比例
117 const sizeInVw = (size / 750) * 100; // 转换为vw单位的百分比 136 const sizeInVw = (size / 750) * 100; // 转换为vw单位的百分比
118 const aspectRatio = windowWidth / windowHeight; 137 const aspectRatio = windowWidth / windowHeight;
119 const radiusPercent = (sizeInVw / 2) / aspectRatio; // 转换为高度百分比的半径 138 const radiusPercent = (sizeInVw / 2) / aspectRatio; // 转换为高度百分比的半径
120 - 139 +
121 // 定义更严格的安全区域,确保积分不会跑出屏幕 140 // 定义更严格的安全区域,确保积分不会跑出屏幕
122 const safeMargin = Math.max(radiusPercent * 1.2, 8); // 至少8%的安全边距 141 const safeMargin = Math.max(radiusPercent * 1.2, 8); // 至少8%的安全边距
123 const minX = safeMargin; 142 const minX = safeMargin;
124 const maxX = 100 - safeMargin; 143 const maxX = 100 - safeMargin;
125 const minY = safeMargin + 5; // 顶部额外5%边距 144 const minY = safeMargin + 5; // 顶部额外5%边距
126 const maxY = Math.min(60, 100 - safeMargin); // 限制在视图的顶部60%或安全区域内 145 const maxY = Math.min(60, 100 - safeMargin); // 限制在视图的顶部60%或安全区域内
127 - 146 +
128 // 确保安全区域有效 147 // 确保安全区域有效
129 if (minX >= maxX || minY >= maxY) { 148 if (minX >= maxX || minY >= maxY) {
130 console.warn('安全区域过小,使用默认位置'); 149 console.warn('安全区域过小,使用默认位置');
...@@ -147,7 +166,7 @@ const generatePointsData = () => { ...@@ -147,7 +166,7 @@ const generatePointsData = () => {
147 // 在计算出的边界内生成位置 166 // 在计算出的边界内生成位置
148 x = Math.random() * (maxX - minX) + minX; 167 x = Math.random() * (maxX - minX) + minX;
149 y = Math.random() * (maxY - minY) + minY; 168 y = Math.random() * (maxY - minY) + minY;
150 - 169 +
151 // 二次检查边界,确保不会超出屏幕 170 // 二次检查边界,确保不会超出屏幕
152 x = Math.max(safeMargin, Math.min(100 - safeMargin, x)); 171 x = Math.max(safeMargin, Math.min(100 - safeMargin, x));
153 y = Math.max(safeMargin, Math.min(maxY, y)); 172 y = Math.max(safeMargin, Math.min(maxY, y));
...@@ -189,16 +208,16 @@ const getItemStyle = (item) => { ...@@ -189,16 +208,16 @@ const getItemStyle = (item) => {
189 const maxValue = Math.max(...(floatingItems.value.map(i => i.points).length > 0 ? floatingItems.value.map(i => i.points) : [1])); 208 const maxValue = Math.max(...(floatingItems.value.map(i => i.points).length > 0 ? floatingItems.value.map(i => i.points) : [1]));
190 const sizeRatio = item.points / maxValue; 209 const sizeRatio = item.points / maxValue;
191 const size = baseSize + (sizeRatio * 50); // 增大最大额外尺寸从40到50 210 const size = baseSize + (sizeRatio * 50); // 增大最大额外尺寸从40到50
192 - 211 +
193 // 计算动态字体大小 212 // 计算动态字体大小
194 const baseFontSize = 20; // 基础字体大小 rpx 213 const baseFontSize = 20; // 基础字体大小 rpx
195 const maxFontSize = 24; // 最大字体大小 rpx 214 const maxFontSize = 24; // 最大字体大小 rpx
196 const minFontSize = 18; // 最小字体大小 rpx,提高最小值确保可读性 215 const minFontSize = 18; // 最小字体大小 rpx,提高最小值确保可读性
197 - 216 +
198 // 根据圆圈大小和文字长度计算合适的字体大小 217 // 根据圆圈大小和文字长度计算合适的字体大小
199 const labelLength = item.sourceLabel?.length || 0; 218 const labelLength = item.sourceLabel?.length || 0;
200 const pointsLength = (item.points + '分').length; 219 const pointsLength = (item.points + '分').length;
201 - 220 +
202 // 优化字体计算:根据圆圈大小和文字长度动态调整 221 // 优化字体计算:根据圆圈大小和文字长度动态调整
203 let dynamicFontSize = Math.max( 222 let dynamicFontSize = Math.max(
204 minFontSize, 223 minFontSize,
...@@ -207,12 +226,12 @@ const getItemStyle = (item) => { ...@@ -207,12 +226,12 @@ const getItemStyle = (item) => {
207 baseFontSize * (size / 100) * (8 / Math.max(8, labelLength)) // 根据文字长度调整 226 baseFontSize * (size / 100) * (8 / Math.max(8, labelLength)) // 根据文字长度调整
208 ) 227 )
209 ); 228 );
210 - 229 +
211 // 确保长文字能在一行显示 230 // 确保长文字能在一行显示
212 if (labelLength > 4) { 231 if (labelLength > 4) {
213 dynamicFontSize = Math.max(minFontSize, dynamicFontSize * (4 / labelLength)); 232 dynamicFontSize = Math.max(minFontSize, dynamicFontSize * (4 / labelLength));
214 } 233 }
215 - 234 +
216 // 确保字体大小为整数 235 // 确保字体大小为整数
217 dynamicFontSize = Math.round(dynamicFontSize); 236 dynamicFontSize = Math.round(dynamicFontSize);
218 237
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
4 <view class="center-circle1"> 4 <view class="center-circle1">
5 <view class="total-points" @tap="handleGoToRewards"> 5 <view class="total-points" @tap="handleGoToRewards">
6 <text v-if="!isOwner" class="family-points-label">家庭总积分</text> 6 <text v-if="!isOwner" class="family-points-label">家庭总积分</text>
7 - <text class="points-number">{{ animatedTotalPoints }}分</text> 7 + <text class="points-number" :style="{ fontSize: dynamicFontSize }">{{ animatedTotalPoints }}分</text>
8 <text v-if="isOwner" class="points-label">去兑换</text> 8 <text v-if="isOwner" class="points-label">去兑换</text>
9 </view> 9 </view>
10 </view> 10 </view>
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
12 </template> 12 </template>
13 13
14 <script setup> 14 <script setup>
15 -import { ref, watch, onMounted, defineProps } from 'vue' 15 +import { ref, watch, onMounted, defineProps, computed } from 'vue'
16 import Taro from '@tarojs/taro' 16 import Taro from '@tarojs/taro'
17 17
18 // 定义props 18 // 定义props
...@@ -36,6 +36,25 @@ const props = defineProps({ ...@@ -36,6 +36,25 @@ const props = defineProps({
36 const animatedTotalPoints = ref(0) 36 const animatedTotalPoints = ref(0)
37 37
38 /** 38 /**
39 + * 根据数值长度动态计算字体大小
40 + */
41 +const dynamicFontSize = computed(() => {
42 + const pointsStr = animatedTotalPoints.value + '分'
43 + const length = pointsStr.length
44 +
45 + // 基础字体大小36rpx,超过6位数开始缩小
46 + if (length <= 6) {
47 + return '36rpx'
48 + } else if (length <= 8) {
49 + return '32rpx'
50 + } else if (length <= 10) {
51 + return '28rpx'
52 + } else {
53 + return '24rpx'
54 + }
55 +})
56 +
57 +/**
39 * 数字滚动动画 58 * 数字滚动动画
40 * @param {number} start - 动画开始值 59 * @param {number} start - 动画开始值
41 * @param {number} end - 动画结束值 60 * @param {number} end - 动画结束值
......