fix(PointsList): 修复列表高度计算问题并添加平板设备适配
refactor(PointsList): 优化高度计算逻辑,添加重试机制和设备适配 style: 统一按钮和文本的字体大小样式
Showing
3 changed files
with
389 additions
and
19 deletions
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2022-09-19 14:11:06 | 2 | * @Date: 2022-09-19 14:11:06 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-09-16 11:16:53 | 4 | + * @LastEditTime: 2025-09-20 22:26:29 |
| 5 | * @FilePath: /lls_program/src/pages/MyFamily/index.vue | 5 | * @FilePath: /lls_program/src/pages/MyFamily/index.vue |
| 6 | * @Description: 我的家庭页面 - 展示用户加入的家庭列表 | 6 | * @Description: 我的家庭页面 - 展示用户加入的家庭列表 |
| 7 | --> | 7 | --> |
| ... | @@ -117,7 +117,7 @@ | ... | @@ -117,7 +117,7 @@ |
| 117 | <view v-if="isShowBtn" class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-100 p-4 z-10"> | 117 | <view v-if="isShowBtn" class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-100 p-4 z-10"> |
| 118 | <view | 118 | <view |
| 119 | @tap="joinNewFamily" | 119 | @tap="joinNewFamily" |
| 120 | - class="w-full bg-blue-500 text-white text-center py-3 rounded-lg font-medium" | 120 | + class="w-full bg-blue-500 text-white text-center py-3 rounded-lg font-medium text-sm" |
| 121 | > | 121 | > |
| 122 | 加入新家庭 | 122 | 加入新家庭 |
| 123 | </view> | 123 | </view> |
| ... | @@ -197,13 +197,13 @@ | ... | @@ -197,13 +197,13 @@ |
| 197 | <view class="flex gap-3"> | 197 | <view class="flex gap-3"> |
| 198 | <view | 198 | <view |
| 199 | @tap="closeMemberPopup" | 199 | @tap="closeMemberPopup" |
| 200 | - class="flex-1 py-3 bg-gray-200 text-gray-700 text-center rounded-lg" | 200 | + class="flex-1 py-3 bg-gray-200 text-gray-700 text-center rounded-lg text-sm" |
| 201 | > | 201 | > |
| 202 | 关闭 | 202 | 关闭 |
| 203 | </view> | 203 | </view> |
| 204 | <view | 204 | <view |
| 205 | @tap="removeSelectedMembers" | 205 | @tap="removeSelectedMembers" |
| 206 | - class="flex-1 py-3 bg-red-500 text-white text-center rounded-lg" | 206 | + class="flex-1 py-3 bg-red-500 text-white text-center rounded-lg text-sm" |
| 207 | :class="selectedMembers.length === 0 ? 'opacity-50' : ''" | 207 | :class="selectedMembers.length === 0 ? 'opacity-50' : ''" |
| 208 | > | 208 | > |
| 209 | 移除 ({{ selectedMembers.length }}) | 209 | 移除 ({{ selectedMembers.length }}) | ... | ... |
| ... | @@ -8,7 +8,7 @@ | ... | @@ -8,7 +8,7 @@ |
| 8 | <!-- Points display --> | 8 | <!-- Points display --> |
| 9 | <view class="pt-4 pb-6 flex flex-col items-center"> | 9 | <view class="pt-4 pb-6 flex flex-col items-center"> |
| 10 | <h2 class="text-4xl font-bold text-white mb-1">{{ totalPoints }}</h2> | 10 | <h2 class="text-4xl font-bold text-white mb-1">{{ totalPoints }}</h2> |
| 11 | - <p class="text-white text-opacity-80">当前可用积分</p> | 11 | + <p class="text-white text-opacity-80 text-sm">当前可用积分</p> |
| 12 | </view> | 12 | </view> |
| 13 | <!-- Points strategy section --> | 13 | <!-- Points strategy section --> |
| 14 | <view class="bg-white rounded-t-3xl px-4 pt-5"> | 14 | <view class="bg-white rounded-t-3xl px-4 pt-5"> | ... | ... |
| ... | @@ -326,12 +326,23 @@ const categorySectionHeight = ref(0) | ... | @@ -326,12 +326,23 @@ const categorySectionHeight = ref(0) |
| 326 | */ | 326 | */ |
| 327 | const scrollStyle = computed(() => { | 327 | const scrollStyle = computed(() => { |
| 328 | const totalFixedHeight = searchSectionHeight.value + categorySectionHeight.value | 328 | const totalFixedHeight = searchSectionHeight.value + categorySectionHeight.value |
| 329 | + | ||
| 330 | + // 添加安全边距,避免内容被遮挡 | ||
| 331 | + const safeMargin = 20 | ||
| 332 | + const finalHeight = totalFixedHeight + safeMargin | ||
| 333 | + | ||
| 329 | return { | 334 | return { |
| 330 | - height: `calc(100vh - ${totalFixedHeight}rpx)` | 335 | + height: `calc(100vh - ${finalHeight}rpx)`, |
| 336 | + minHeight: '400rpx' // 设置最小高度,防止在某些设备上过小 | ||
| 331 | } | 337 | } |
| 332 | }) | 338 | }) |
| 333 | 339 | ||
| 334 | /** | 340 | /** |
| 341 | + * 获取系统信息 | ||
| 342 | + */ | ||
| 343 | +const systemInfo = ref({}) | ||
| 344 | + | ||
| 345 | +/** | ||
| 335 | * 获取元素高度 | 346 | * 获取元素高度 |
| 336 | * @param {string} selector - 元素选择器 | 347 | * @param {string} selector - 元素选择器 |
| 337 | * @returns {Promise<number>} 元素高度(rpx) | 348 | * @returns {Promise<number>} 元素高度(rpx) |
| ... | @@ -340,10 +351,14 @@ const getElementHeight = (selector) => { | ... | @@ -340,10 +351,14 @@ const getElementHeight = (selector) => { |
| 340 | return new Promise((resolve) => { | 351 | return new Promise((resolve) => { |
| 341 | const query = Taro.createSelectorQuery() | 352 | const query = Taro.createSelectorQuery() |
| 342 | query.select(selector).boundingClientRect((rect) => { | 353 | query.select(selector).boundingClientRect((rect) => { |
| 343 | - if (rect) { | 354 | + if (rect && rect.height > 0) { |
| 344 | - // 将px转换为rpx | 355 | + // 根据设备像素比动态计算rpx |
| 345 | - const height = rect.height * 2 | 356 | + const pixelRatio = systemInfo.value.pixelRatio || 2 |
| 346 | - resolve(height) | 357 | + const screenWidth = systemInfo.value.screenWidth || 375 |
| 358 | + // 标准转换:750rpx = 屏幕宽度px | ||
| 359 | + const rpxRatio = 750 / screenWidth | ||
| 360 | + const height = rect.height * rpxRatio | ||
| 361 | + resolve(Math.ceil(height)) | ||
| 347 | } else { | 362 | } else { |
| 348 | resolve(0) | 363 | resolve(0) |
| 349 | } | 364 | } |
| ... | @@ -356,16 +371,40 @@ const getElementHeight = (selector) => { | ... | @@ -356,16 +371,40 @@ const getElementHeight = (selector) => { |
| 356 | */ | 371 | */ |
| 357 | const calculateFixedHeight = async () => { | 372 | const calculateFixedHeight = async () => { |
| 358 | try { | 373 | try { |
| 359 | - const searchHeight = await getElementHeight('.search-section') | 374 | + // 获取系统信息 |
| 360 | - const categoryHeight = await getElementHeight('.category-section') | 375 | + systemInfo.value = await Taro.getWindowInfo() |
| 376 | + | ||
| 377 | + // 多次尝试获取高度,确保DOM完全渲染 | ||
| 378 | + let attempts = 0 | ||
| 379 | + const maxAttempts = 3 | ||
| 380 | + | ||
| 381 | + while (attempts < maxAttempts) { | ||
| 382 | + const searchHeight = await getElementHeight('.search-section') | ||
| 383 | + const categoryHeight = await getElementHeight('.category-section') | ||
| 384 | + | ||
| 385 | + // 如果获取到有效高度,则使用 | ||
| 386 | + if (searchHeight > 0 && categoryHeight > 0) { | ||
| 387 | + searchSectionHeight.value = searchHeight | ||
| 388 | + categorySectionHeight.value = categoryHeight | ||
| 389 | + return | ||
| 390 | + } | ||
| 391 | + | ||
| 392 | + attempts++ | ||
| 393 | + // 等待更长时间再重试 | ||
| 394 | + await new Promise(resolve => setTimeout(resolve, 200)) | ||
| 395 | + } | ||
| 396 | + | ||
| 397 | + // 如果多次尝试都失败,使用基于设备的默认值 | ||
| 398 | + const isTablet = systemInfo.value.screenWidth >= 768 | ||
| 399 | + searchSectionHeight.value = isTablet ? 180 : 144 // 平板设备使用更大的默认值 | ||
| 400 | + categorySectionHeight.value = isTablet ? 240 : 200 | ||
| 361 | 401 | ||
| 362 | - searchSectionHeight.value = searchHeight | ||
| 363 | - categorySectionHeight.value = categoryHeight | ||
| 364 | } catch (error) { | 402 | } catch (error) { |
| 365 | console.error('计算高度失败:', error) | 403 | console.error('计算高度失败:', error) |
| 366 | - // 使用默认值 | 404 | + // 使用保守的默认值 |
| 367 | - searchSectionHeight.value = 144 // 搜索区域默认高度 | 405 | + const isTablet = systemInfo.value?.screenWidth >= 768 |
| 368 | - categorySectionHeight.value = 200 // 分类区域默认高度 | 406 | + searchSectionHeight.value = isTablet ? 180 : 144 |
| 407 | + categorySectionHeight.value = isTablet ? 240 : 200 | ||
| 369 | } | 408 | } |
| 370 | } | 409 | } |
| 371 | 410 | ||
| ... | @@ -431,11 +470,29 @@ const closeDetail = () => { | ... | @@ -431,11 +470,29 @@ const closeDetail = () => { |
| 431 | } | 470 | } |
| 432 | 471 | ||
| 433 | // ==================== 生命周期 ==================== | 472 | // ==================== 生命周期 ==================== |
| 434 | -onMounted(() => { | 473 | +onMounted(async () => { |
| 474 | + // 先获取系统信息 | ||
| 475 | + try { | ||
| 476 | + systemInfo.value = await Taro.getWindowInfo() | ||
| 477 | + } catch (error) { | ||
| 478 | + console.error('获取系统信息失败:', error) | ||
| 479 | + } | ||
| 480 | + | ||
| 435 | // 延时计算高度,确保DOM渲染完成 | 481 | // 延时计算高度,确保DOM渲染完成 |
| 482 | + // 对于平板设备,需要更长的等待时间 | ||
| 483 | + const isTablet = systemInfo.value?.screenWidth >= 768 | ||
| 484 | + const delay = isTablet ? 300 : 150 | ||
| 485 | + | ||
| 436 | setTimeout(() => { | 486 | setTimeout(() => { |
| 437 | calculateFixedHeight() | 487 | calculateFixedHeight() |
| 438 | - }, 100) | 488 | + }, delay) |
| 489 | + | ||
| 490 | + // 监听窗口大小变化,重新计算高度 | ||
| 491 | + Taro.onWindowResize(() => { | ||
| 492 | + setTimeout(() => { | ||
| 493 | + calculateFixedHeight() | ||
| 494 | + }, 100) | ||
| 495 | + }) | ||
| 439 | }) | 496 | }) |
| 440 | </script> | 497 | </script> |
| 441 | 498 | ||
| ... | @@ -444,3 +501,316 @@ export default { | ... | @@ -444,3 +501,316 @@ export default { |
| 444 | name: 'PointsListPage' | 501 | name: 'PointsListPage' |
| 445 | } | 502 | } |
| 446 | </script> | 503 | </script> |
| 504 | + | ||
| 505 | +<style lang="less" scoped> | ||
| 506 | +.points-list-page { | ||
| 507 | + height: 100vh; | ||
| 508 | + display: flex; | ||
| 509 | + flex-direction: column; | ||
| 510 | + | ||
| 511 | + .search-section { | ||
| 512 | + flex-shrink: 0; | ||
| 513 | + padding: 20rpx; | ||
| 514 | + | ||
| 515 | + // 平板设备适配 | ||
| 516 | + @media (min-width: 768px) { | ||
| 517 | + padding: 30rpx 40rpx; | ||
| 518 | + } | ||
| 519 | + | ||
| 520 | + .search-box { | ||
| 521 | + .search-input { | ||
| 522 | + width: 100%; | ||
| 523 | + height: 80rpx; | ||
| 524 | + padding: 0 20rpx; | ||
| 525 | + border-radius: 40rpx; | ||
| 526 | + background-color: #f5f5f5; | ||
| 527 | + font-size: 28rpx; | ||
| 528 | + | ||
| 529 | + // 平板设备适配 | ||
| 530 | + @media (min-width: 768px) { | ||
| 531 | + height: 100rpx; | ||
| 532 | + font-size: 32rpx; | ||
| 533 | + padding: 0 30rpx; | ||
| 534 | + } | ||
| 535 | + } | ||
| 536 | + } | ||
| 537 | + } | ||
| 538 | + | ||
| 539 | + .category-section { | ||
| 540 | + flex-shrink: 0; | ||
| 541 | + padding: 20rpx; | ||
| 542 | + | ||
| 543 | + // 平板设备适配 | ||
| 544 | + @media (min-width: 768px) { | ||
| 545 | + padding: 30rpx 40rpx; | ||
| 546 | + } | ||
| 547 | + | ||
| 548 | + .category-title { | ||
| 549 | + font-size: 32rpx; | ||
| 550 | + font-weight: bold; | ||
| 551 | + margin-bottom: 20rpx; | ||
| 552 | + | ||
| 553 | + // 平板设备适配 | ||
| 554 | + @media (min-width: 768px) { | ||
| 555 | + font-size: 36rpx; | ||
| 556 | + margin-bottom: 30rpx; | ||
| 557 | + } | ||
| 558 | + } | ||
| 559 | + | ||
| 560 | + .category-grid { | ||
| 561 | + display: flex; | ||
| 562 | + flex-wrap: wrap; | ||
| 563 | + gap: 20rpx; | ||
| 564 | + | ||
| 565 | + // 平板设备适配 | ||
| 566 | + @media (min-width: 768px) { | ||
| 567 | + gap: 30rpx; | ||
| 568 | + } | ||
| 569 | + | ||
| 570 | + .category-item { | ||
| 571 | + padding: 16rpx 32rpx; | ||
| 572 | + border-radius: 40rpx; | ||
| 573 | + background-color: #f8f8f8; | ||
| 574 | + border: 2rpx solid transparent; | ||
| 575 | + transition: all 0.3s ease; | ||
| 576 | + | ||
| 577 | + // 平板设备适配 | ||
| 578 | + @media (min-width: 768px) { | ||
| 579 | + padding: 20rpx 40rpx; | ||
| 580 | + font-size: 30rpx; | ||
| 581 | + } | ||
| 582 | + | ||
| 583 | + &.active { | ||
| 584 | + background-color: #007aff; | ||
| 585 | + color: white; | ||
| 586 | + } | ||
| 587 | + | ||
| 588 | + .category-name { | ||
| 589 | + font-size: 28rpx; | ||
| 590 | + | ||
| 591 | + // 平板设备适配 | ||
| 592 | + @media (min-width: 768px) { | ||
| 593 | + font-size: 32rpx; | ||
| 594 | + } | ||
| 595 | + } | ||
| 596 | + } | ||
| 597 | + } | ||
| 598 | + } | ||
| 599 | + | ||
| 600 | + .points-list-section { | ||
| 601 | + flex: 1; | ||
| 602 | + overflow: hidden; | ||
| 603 | + | ||
| 604 | + .points-list { | ||
| 605 | + height: 100%; | ||
| 606 | + | ||
| 607 | + .points-items { | ||
| 608 | + padding: 0 20rpx 20rpx; | ||
| 609 | + | ||
| 610 | + // 平板设备适配 | ||
| 611 | + @media (min-width: 768px) { | ||
| 612 | + padding: 0 40rpx 40rpx; | ||
| 613 | + } | ||
| 614 | + | ||
| 615 | + .points-item { | ||
| 616 | + display: flex; | ||
| 617 | + align-items: center; | ||
| 618 | + padding: 30rpx 20rpx; | ||
| 619 | + margin-bottom: 20rpx; | ||
| 620 | + background-color: white; | ||
| 621 | + border-radius: 20rpx; | ||
| 622 | + box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1); | ||
| 623 | + | ||
| 624 | + // 平板设备适配 | ||
| 625 | + @media (min-width: 768px) { | ||
| 626 | + padding: 40rpx 30rpx; | ||
| 627 | + margin-bottom: 30rpx; | ||
| 628 | + border-radius: 24rpx; | ||
| 629 | + } | ||
| 630 | + | ||
| 631 | + .points-item-left { | ||
| 632 | + flex: 1; | ||
| 633 | + | ||
| 634 | + .points-content { | ||
| 635 | + .points-title { | ||
| 636 | + font-size: 32rpx; | ||
| 637 | + font-weight: bold; | ||
| 638 | + color: #333; | ||
| 639 | + margin-bottom: 10rpx; | ||
| 640 | + display: block; | ||
| 641 | + | ||
| 642 | + // 平板设备适配 | ||
| 643 | + @media (min-width: 768px) { | ||
| 644 | + font-size: 36rpx; | ||
| 645 | + margin-bottom: 15rpx; | ||
| 646 | + } | ||
| 647 | + } | ||
| 648 | + | ||
| 649 | + .points-desc { | ||
| 650 | + font-size: 26rpx; | ||
| 651 | + color: #666; | ||
| 652 | + margin-bottom: 15rpx; | ||
| 653 | + display: block; | ||
| 654 | + line-height: 1.4; | ||
| 655 | + | ||
| 656 | + // 平板设备适配 | ||
| 657 | + @media (min-width: 768px) { | ||
| 658 | + font-size: 30rpx; | ||
| 659 | + margin-bottom: 20rpx; | ||
| 660 | + } | ||
| 661 | + } | ||
| 662 | + | ||
| 663 | + .points-reward { | ||
| 664 | + .reward-text { | ||
| 665 | + font-size: 24rpx; | ||
| 666 | + color: #007aff; | ||
| 667 | + font-weight: bold; | ||
| 668 | + | ||
| 669 | + // 平板设备适配 | ||
| 670 | + @media (min-width: 768px) { | ||
| 671 | + font-size: 28rpx; | ||
| 672 | + } | ||
| 673 | + } | ||
| 674 | + } | ||
| 675 | + } | ||
| 676 | + } | ||
| 677 | + | ||
| 678 | + .points-item-right { | ||
| 679 | + margin-left: 20rpx; | ||
| 680 | + | ||
| 681 | + // 平板设备适配 | ||
| 682 | + @media (min-width: 768px) { | ||
| 683 | + margin-left: 30rpx; | ||
| 684 | + } | ||
| 685 | + | ||
| 686 | + .arrow-text { | ||
| 687 | + font-size: 32rpx; | ||
| 688 | + color: #ccc; | ||
| 689 | + | ||
| 690 | + // 平板设备适配 | ||
| 691 | + @media (min-width: 768px) { | ||
| 692 | + font-size: 36rpx; | ||
| 693 | + } | ||
| 694 | + } | ||
| 695 | + } | ||
| 696 | + } | ||
| 697 | + } | ||
| 698 | + | ||
| 699 | + .empty-state { | ||
| 700 | + display: flex; | ||
| 701 | + justify-content: center; | ||
| 702 | + align-items: center; | ||
| 703 | + height: 400rpx; | ||
| 704 | + | ||
| 705 | + .empty-text { | ||
| 706 | + font-size: 28rpx; | ||
| 707 | + color: #999; | ||
| 708 | + | ||
| 709 | + // 平板设备适配 | ||
| 710 | + @media (min-width: 768px) { | ||
| 711 | + font-size: 32rpx; | ||
| 712 | + } | ||
| 713 | + } | ||
| 714 | + } | ||
| 715 | + } | ||
| 716 | + } | ||
| 717 | +} | ||
| 718 | + | ||
| 719 | +// 详情弹窗样式 | ||
| 720 | +.detail-popup { | ||
| 721 | + height: 100%; | ||
| 722 | + display: flex; | ||
| 723 | + flex-direction: column; | ||
| 724 | + background-color: #f8f8f8; | ||
| 725 | + | ||
| 726 | + .detail-header { | ||
| 727 | + display: flex; | ||
| 728 | + justify-content: space-between; | ||
| 729 | + align-items: center; | ||
| 730 | + padding: 40rpx 30rpx; | ||
| 731 | + background-color: white; | ||
| 732 | + border-bottom: 2rpx solid #eee; | ||
| 733 | + | ||
| 734 | + // 平板设备适配 | ||
| 735 | + @media (min-width: 768px) { | ||
| 736 | + padding: 50rpx 40rpx; | ||
| 737 | + } | ||
| 738 | + | ||
| 739 | + .detail-title { | ||
| 740 | + font-size: 36rpx; | ||
| 741 | + font-weight: bold; | ||
| 742 | + color: #333; | ||
| 743 | + | ||
| 744 | + // 平板设备适配 | ||
| 745 | + @media (min-width: 768px) { | ||
| 746 | + font-size: 40rpx; | ||
| 747 | + } | ||
| 748 | + } | ||
| 749 | + | ||
| 750 | + .close-btn1 { | ||
| 751 | + padding: 10rpx 20rpx; | ||
| 752 | + | ||
| 753 | + .close-text { | ||
| 754 | + font-size: 28rpx; | ||
| 755 | + color: #007aff; | ||
| 756 | + | ||
| 757 | + // 平板设备适配 | ||
| 758 | + @media (min-width: 768px) { | ||
| 759 | + font-size: 32rpx; | ||
| 760 | + } | ||
| 761 | + } | ||
| 762 | + } | ||
| 763 | + } | ||
| 764 | + | ||
| 765 | + .detail-content { | ||
| 766 | + flex: 1; | ||
| 767 | + | ||
| 768 | + .detail-body { | ||
| 769 | + padding: 30rpx; | ||
| 770 | + | ||
| 771 | + // 平板设备适配 | ||
| 772 | + @media (min-width: 768px) { | ||
| 773 | + padding: 40rpx; | ||
| 774 | + } | ||
| 775 | + | ||
| 776 | + .detail-section { | ||
| 777 | + margin-bottom: 40rpx; | ||
| 778 | + padding: 30rpx; | ||
| 779 | + background-color: white; | ||
| 780 | + border-radius: 20rpx; | ||
| 781 | + | ||
| 782 | + // 平板设备适配 | ||
| 783 | + @media (min-width: 768px) { | ||
| 784 | + margin-bottom: 50rpx; | ||
| 785 | + padding: 40rpx; | ||
| 786 | + border-radius: 24rpx; | ||
| 787 | + } | ||
| 788 | + | ||
| 789 | + .section-title { | ||
| 790 | + font-size: 32rpx; | ||
| 791 | + font-weight: bold; | ||
| 792 | + color: #333; | ||
| 793 | + margin-bottom: 20rpx; | ||
| 794 | + | ||
| 795 | + // 平板设备适配 | ||
| 796 | + @media (min-width: 768px) { | ||
| 797 | + font-size: 36rpx; | ||
| 798 | + margin-bottom: 30rpx; | ||
| 799 | + } | ||
| 800 | + } | ||
| 801 | + | ||
| 802 | + .section-content { | ||
| 803 | + font-size: 28rpx; | ||
| 804 | + color: #666; | ||
| 805 | + line-height: 1.5; | ||
| 806 | + | ||
| 807 | + // 平板设备适配 | ||
| 808 | + @media (min-width: 768px) { | ||
| 809 | + font-size: 32rpx; | ||
| 810 | + } | ||
| 811 | + } | ||
| 812 | + } | ||
| 813 | + } | ||
| 814 | + } | ||
| 815 | +} | ||
| 816 | +</style> | ... | ... |
-
Please register or login to post a comment