hookehuyr

fix(PointsList): 修复列表高度计算问题并添加平板设备适配

refactor(PointsList): 优化高度计算逻辑,添加重试机制和设备适配
style: 统一按钮和文本的字体大小样式
<!--
* @Date: 2022-09-19 14:11:06
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-09-16 11:16:53
* @LastEditTime: 2025-09-20 22:26:29
* @FilePath: /lls_program/src/pages/MyFamily/index.vue
* @Description: 我的家庭页面 - 展示用户加入的家庭列表
-->
......@@ -117,7 +117,7 @@
<view v-if="isShowBtn" class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-100 p-4 z-10">
<view
@tap="joinNewFamily"
class="w-full bg-blue-500 text-white text-center py-3 rounded-lg font-medium"
class="w-full bg-blue-500 text-white text-center py-3 rounded-lg font-medium text-sm"
>
加入新家庭
</view>
......@@ -197,13 +197,13 @@
<view class="flex gap-3">
<view
@tap="closeMemberPopup"
class="flex-1 py-3 bg-gray-200 text-gray-700 text-center rounded-lg"
class="flex-1 py-3 bg-gray-200 text-gray-700 text-center rounded-lg text-sm"
>
关闭
</view>
<view
@tap="removeSelectedMembers"
class="flex-1 py-3 bg-red-500 text-white text-center rounded-lg"
class="flex-1 py-3 bg-red-500 text-white text-center rounded-lg text-sm"
:class="selectedMembers.length === 0 ? 'opacity-50' : ''"
>
移除 ({{ selectedMembers.length }})
......
......@@ -8,7 +8,7 @@
<!-- Points display -->
<view class="pt-4 pb-6 flex flex-col items-center">
<h2 class="text-4xl font-bold text-white mb-1">{{ totalPoints }}</h2>
<p class="text-white text-opacity-80">当前可用积分</p>
<p class="text-white text-opacity-80 text-sm">当前可用积分</p>
</view>
<!-- Points strategy section -->
<view class="bg-white rounded-t-3xl px-4 pt-5">
......
......@@ -326,12 +326,23 @@ const categorySectionHeight = ref(0)
*/
const scrollStyle = computed(() => {
const totalFixedHeight = searchSectionHeight.value + categorySectionHeight.value
// 添加安全边距,避免内容被遮挡
const safeMargin = 20
const finalHeight = totalFixedHeight + safeMargin
return {
height: `calc(100vh - ${totalFixedHeight}rpx)`
height: `calc(100vh - ${finalHeight}rpx)`,
minHeight: '400rpx' // 设置最小高度,防止在某些设备上过小
}
})
/**
* 获取系统信息
*/
const systemInfo = ref({})
/**
* 获取元素高度
* @param {string} selector - 元素选择器
* @returns {Promise<number>} 元素高度(rpx)
......@@ -340,10 +351,14 @@ const getElementHeight = (selector) => {
return new Promise((resolve) => {
const query = Taro.createSelectorQuery()
query.select(selector).boundingClientRect((rect) => {
if (rect) {
// 将px转换为rpx
const height = rect.height * 2
resolve(height)
if (rect && rect.height > 0) {
// 根据设备像素比动态计算rpx
const pixelRatio = systemInfo.value.pixelRatio || 2
const screenWidth = systemInfo.value.screenWidth || 375
// 标准转换:750rpx = 屏幕宽度px
const rpxRatio = 750 / screenWidth
const height = rect.height * rpxRatio
resolve(Math.ceil(height))
} else {
resolve(0)
}
......@@ -356,16 +371,40 @@ const getElementHeight = (selector) => {
*/
const calculateFixedHeight = async () => {
try {
const searchHeight = await getElementHeight('.search-section')
const categoryHeight = await getElementHeight('.category-section')
// 获取系统信息
systemInfo.value = await Taro.getWindowInfo()
// 多次尝试获取高度,确保DOM完全渲染
let attempts = 0
const maxAttempts = 3
while (attempts < maxAttempts) {
const searchHeight = await getElementHeight('.search-section')
const categoryHeight = await getElementHeight('.category-section')
// 如果获取到有效高度,则使用
if (searchHeight > 0 && categoryHeight > 0) {
searchSectionHeight.value = searchHeight
categorySectionHeight.value = categoryHeight
return
}
attempts++
// 等待更长时间再重试
await new Promise(resolve => setTimeout(resolve, 200))
}
// 如果多次尝试都失败,使用基于设备的默认值
const isTablet = systemInfo.value.screenWidth >= 768
searchSectionHeight.value = isTablet ? 180 : 144 // 平板设备使用更大的默认值
categorySectionHeight.value = isTablet ? 240 : 200
searchSectionHeight.value = searchHeight
categorySectionHeight.value = categoryHeight
} catch (error) {
console.error('计算高度失败:', error)
// 使用默认值
searchSectionHeight.value = 144 // 搜索区域默认高度
categorySectionHeight.value = 200 // 分类区域默认高度
// 使用保守的默认值
const isTablet = systemInfo.value?.screenWidth >= 768
searchSectionHeight.value = isTablet ? 180 : 144
categorySectionHeight.value = isTablet ? 240 : 200
}
}
......@@ -431,11 +470,29 @@ const closeDetail = () => {
}
// ==================== 生命周期 ====================
onMounted(() => {
onMounted(async () => {
// 先获取系统信息
try {
systemInfo.value = await Taro.getWindowInfo()
} catch (error) {
console.error('获取系统信息失败:', error)
}
// 延时计算高度,确保DOM渲染完成
// 对于平板设备,需要更长的等待时间
const isTablet = systemInfo.value?.screenWidth >= 768
const delay = isTablet ? 300 : 150
setTimeout(() => {
calculateFixedHeight()
}, 100)
}, delay)
// 监听窗口大小变化,重新计算高度
Taro.onWindowResize(() => {
setTimeout(() => {
calculateFixedHeight()
}, 100)
})
})
</script>
......@@ -444,3 +501,316 @@ export default {
name: 'PointsListPage'
}
</script>
<style lang="less" scoped>
.points-list-page {
height: 100vh;
display: flex;
flex-direction: column;
.search-section {
flex-shrink: 0;
padding: 20rpx;
// 平板设备适配
@media (min-width: 768px) {
padding: 30rpx 40rpx;
}
.search-box {
.search-input {
width: 100%;
height: 80rpx;
padding: 0 20rpx;
border-radius: 40rpx;
background-color: #f5f5f5;
font-size: 28rpx;
// 平板设备适配
@media (min-width: 768px) {
height: 100rpx;
font-size: 32rpx;
padding: 0 30rpx;
}
}
}
}
.category-section {
flex-shrink: 0;
padding: 20rpx;
// 平板设备适配
@media (min-width: 768px) {
padding: 30rpx 40rpx;
}
.category-title {
font-size: 32rpx;
font-weight: bold;
margin-bottom: 20rpx;
// 平板设备适配
@media (min-width: 768px) {
font-size: 36rpx;
margin-bottom: 30rpx;
}
}
.category-grid {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
// 平板设备适配
@media (min-width: 768px) {
gap: 30rpx;
}
.category-item {
padding: 16rpx 32rpx;
border-radius: 40rpx;
background-color: #f8f8f8;
border: 2rpx solid transparent;
transition: all 0.3s ease;
// 平板设备适配
@media (min-width: 768px) {
padding: 20rpx 40rpx;
font-size: 30rpx;
}
&.active {
background-color: #007aff;
color: white;
}
.category-name {
font-size: 28rpx;
// 平板设备适配
@media (min-width: 768px) {
font-size: 32rpx;
}
}
}
}
}
.points-list-section {
flex: 1;
overflow: hidden;
.points-list {
height: 100%;
.points-items {
padding: 0 20rpx 20rpx;
// 平板设备适配
@media (min-width: 768px) {
padding: 0 40rpx 40rpx;
}
.points-item {
display: flex;
align-items: center;
padding: 30rpx 20rpx;
margin-bottom: 20rpx;
background-color: white;
border-radius: 20rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
// 平板设备适配
@media (min-width: 768px) {
padding: 40rpx 30rpx;
margin-bottom: 30rpx;
border-radius: 24rpx;
}
.points-item-left {
flex: 1;
.points-content {
.points-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
display: block;
// 平板设备适配
@media (min-width: 768px) {
font-size: 36rpx;
margin-bottom: 15rpx;
}
}
.points-desc {
font-size: 26rpx;
color: #666;
margin-bottom: 15rpx;
display: block;
line-height: 1.4;
// 平板设备适配
@media (min-width: 768px) {
font-size: 30rpx;
margin-bottom: 20rpx;
}
}
.points-reward {
.reward-text {
font-size: 24rpx;
color: #007aff;
font-weight: bold;
// 平板设备适配
@media (min-width: 768px) {
font-size: 28rpx;
}
}
}
}
}
.points-item-right {
margin-left: 20rpx;
// 平板设备适配
@media (min-width: 768px) {
margin-left: 30rpx;
}
.arrow-text {
font-size: 32rpx;
color: #ccc;
// 平板设备适配
@media (min-width: 768px) {
font-size: 36rpx;
}
}
}
}
}
.empty-state {
display: flex;
justify-content: center;
align-items: center;
height: 400rpx;
.empty-text {
font-size: 28rpx;
color: #999;
// 平板设备适配
@media (min-width: 768px) {
font-size: 32rpx;
}
}
}
}
}
}
// 详情弹窗样式
.detail-popup {
height: 100%;
display: flex;
flex-direction: column;
background-color: #f8f8f8;
.detail-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 40rpx 30rpx;
background-color: white;
border-bottom: 2rpx solid #eee;
// 平板设备适配
@media (min-width: 768px) {
padding: 50rpx 40rpx;
}
.detail-title {
font-size: 36rpx;
font-weight: bold;
color: #333;
// 平板设备适配
@media (min-width: 768px) {
font-size: 40rpx;
}
}
.close-btn1 {
padding: 10rpx 20rpx;
.close-text {
font-size: 28rpx;
color: #007aff;
// 平板设备适配
@media (min-width: 768px) {
font-size: 32rpx;
}
}
}
}
.detail-content {
flex: 1;
.detail-body {
padding: 30rpx;
// 平板设备适配
@media (min-width: 768px) {
padding: 40rpx;
}
.detail-section {
margin-bottom: 40rpx;
padding: 30rpx;
background-color: white;
border-radius: 20rpx;
// 平板设备适配
@media (min-width: 768px) {
margin-bottom: 50rpx;
padding: 40rpx;
border-radius: 24rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
// 平板设备适配
@media (min-width: 768px) {
font-size: 36rpx;
margin-bottom: 30rpx;
}
}
.section-content {
font-size: 28rpx;
color: #666;
line-height: 1.5;
// 平板设备适配
@media (min-width: 768px) {
font-size: 32rpx;
}
}
}
}
}
}
</style>
......