hookehuyr

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

为积分显示组件添加根据数字长度自动调整字体大小的功能,确保长数字的可读性
......@@ -4,7 +4,7 @@
<view class="center-circle">
<view class="total-points" @tap="handleGoToRewards">
<text v-if="!isOwner" class="family-points-label">家庭总积分</text>
<text class="points-number">{{ animatedTotalPoints }}分</text>
<text class="points-number" :style="{ fontSize: dynamicFontSize }">{{ animatedTotalPoints }}分</text>
<text v-if="isOwner" class="points-label">去兑换</text>
</view>
</view>
......@@ -35,7 +35,7 @@
</template>
<script setup>
import { ref, onMounted, defineProps, defineExpose, defineEmits, watch } from 'vue'
import { ref, onMounted, defineProps, defineExpose, defineEmits, watch, computed } from 'vue'
import Taro, { useDidShow } from '@tarojs/taro'
import { collectPointAPI } from '@/api/points'
......@@ -68,6 +68,25 @@ const animatedTotalPoints = ref(props.totalPoints) // 动画中的总积分
const floatingItems = ref([]) // 漂浮的积分项
const isCollecting = ref(false) // 是否正在收集,防止重复触发
/**
* 根据数值长度动态计算字体大小
*/
const dynamicFontSize = computed(() => {
const pointsStr = animatedTotalPoints.value + '分'
const length = pointsStr.length
// 基础字体大小36rpx,超过6位数开始缩小
if (length <= 6) {
return '36rpx'
} else if (length <= 8) {
return '32rpx'
} else if (length <= 10) {
return '28rpx'
} else {
return '24rpx'
}
})
// source_type 中英文映射
const sourceTypeMap = {
'WALKING': '步数积分',
......@@ -111,20 +130,20 @@ const generatePointsData = () => {
// 计算项目大小和半径
const sizeRatio = item.points / maxValue;
const size = baseSize + (sizeRatio * 40); // rpx
// 优化半径计算,确保在不同屏幕尺寸下都能正确计算边界
// 将rpx转换为百分比,考虑屏幕宽度和高度的比例
const sizeInVw = (size / 750) * 100; // 转换为vw单位的百分比
const aspectRatio = windowWidth / windowHeight;
const radiusPercent = (sizeInVw / 2) / aspectRatio; // 转换为高度百分比的半径
// 定义更严格的安全区域,确保积分不会跑出屏幕
const safeMargin = Math.max(radiusPercent * 1.2, 8); // 至少8%的安全边距
const minX = safeMargin;
const maxX = 100 - safeMargin;
const minY = safeMargin + 5; // 顶部额外5%边距
const maxY = Math.min(60, 100 - safeMargin); // 限制在视图的顶部60%或安全区域内
// 确保安全区域有效
if (minX >= maxX || minY >= maxY) {
console.warn('安全区域过小,使用默认位置');
......@@ -147,7 +166,7 @@ const generatePointsData = () => {
// 在计算出的边界内生成位置
x = Math.random() * (maxX - minX) + minX;
y = Math.random() * (maxY - minY) + minY;
// 二次检查边界,确保不会超出屏幕
x = Math.max(safeMargin, Math.min(100 - safeMargin, x));
y = Math.max(safeMargin, Math.min(maxY, y));
......@@ -189,16 +208,16 @@ const getItemStyle = (item) => {
const maxValue = Math.max(...(floatingItems.value.map(i => i.points).length > 0 ? floatingItems.value.map(i => i.points) : [1]));
const sizeRatio = item.points / maxValue;
const size = baseSize + (sizeRatio * 50); // 增大最大额外尺寸从40到50
// 计算动态字体大小
const baseFontSize = 20; // 基础字体大小 rpx
const maxFontSize = 24; // 最大字体大小 rpx
const minFontSize = 18; // 最小字体大小 rpx,提高最小值确保可读性
// 根据圆圈大小和文字长度计算合适的字体大小
const labelLength = item.sourceLabel?.length || 0;
const pointsLength = (item.points + '分').length;
// 优化字体计算:根据圆圈大小和文字长度动态调整
let dynamicFontSize = Math.max(
minFontSize,
......@@ -207,12 +226,12 @@ const getItemStyle = (item) => {
baseFontSize * (size / 100) * (8 / Math.max(8, labelLength)) // 根据文字长度调整
)
);
// 确保长文字能在一行显示
if (labelLength > 4) {
dynamicFontSize = Math.max(minFontSize, dynamicFontSize * (4 / labelLength));
}
// 确保字体大小为整数
dynamicFontSize = Math.round(dynamicFontSize);
......
......@@ -4,7 +4,7 @@
<view class="center-circle1">
<view class="total-points" @tap="handleGoToRewards">
<text v-if="!isOwner" class="family-points-label">家庭总积分</text>
<text class="points-number">{{ animatedTotalPoints }}分</text>
<text class="points-number" :style="{ fontSize: dynamicFontSize }">{{ animatedTotalPoints }}分</text>
<text v-if="isOwner" class="points-label">去兑换</text>
</view>
</view>
......@@ -12,7 +12,7 @@
</template>
<script setup>
import { ref, watch, onMounted, defineProps } from 'vue'
import { ref, watch, onMounted, defineProps, computed } from 'vue'
import Taro from '@tarojs/taro'
// 定义props
......@@ -36,6 +36,25 @@ const props = defineProps({
const animatedTotalPoints = ref(0)
/**
* 根据数值长度动态计算字体大小
*/
const dynamicFontSize = computed(() => {
const pointsStr = animatedTotalPoints.value + '分'
const length = pointsStr.length
// 基础字体大小36rpx,超过6位数开始缩小
if (length <= 6) {
return '36rpx'
} else if (length <= 8) {
return '32rpx'
} else if (length <= 10) {
return '28rpx'
} else {
return '24rpx'
}
})
/**
* 数字滚动动画
* @param {number} start - 动画开始值
* @param {number} end - 动画结束值
......