6.4 KiB
6.4 KiB
Square Tab 滚动行为差异化设计
日期: 2026-06-11 状态: 已通过 spec 评审 作者: Claude (brainstorming session)
背景
square.vue 页面通过 activeContentTab 切换 星河 / 星榜 / 广场 三个内容。
当前所有 tab 共用同一个外层 <scroll-view class="content-wrapper" scroll-y>,
导致三个 tab 的滚动行为完全一致:都是页面整体滚动。
需求:三个 tab 的滚动行为需要差异化:
| Tab | 期望行为 |
|---|---|
星河 (xinghe) |
完全禁用滚动(外层 + 内部都不滚) |
星榜 (xingbang) |
页面不滚动,只有 HotCategoryBlock 内部 grid 区域可滚 |
广场 (guangchang) |
保持当前行为(外层 scroll-view 整体滚动) |
目标
- 不重构页面骨架
- 不修改
StarGalaxy任何样式(保留top: -128rpx、min-height: 1440rpx等视觉设计) - 仅通过外层
scroll-view的scroll-y动态绑定 +HotCategoryBlock内部增加独立 scroll 容器达成 - 切换 tab 时重置外层 scrollTop,避免残留滚动位置
设计
1. 模板改动 (frontend/pages/square/square.vue)
唯一改动:把 <scroll-view> 上的 scroll-y 从静态改为动态绑定。
<scroll-view
class="content-wrapper"
:scroll-y="activeContentTab === 'guangchang'"
:show-scrollbar="false"
:bounce="false"
@scroll="onScroll"
@scrolltolower="handleScrollToLower"
>
<!-- banner + ContentTabs + 三个 tab 内容(结构完全不变) -->
<view class="banner-section">...</view>
<ContentTabs ... />
<view v-if="activeContentTab === 'xinghe'" class="star-galaxy-wrapper">
<StarGalaxy @cardClick="handleCardClick" />
</view>
<view v-else-if="activeContentTab === 'xingbang'" class="hot-category-wrapper">
<HotCategoryBlock @cardClick="handleCardClick" />
</view>
<CreationGrid
v-if="activeContentTab === 'guangchang'"
@cardClick="handleCardClick"
ref="creationGridRef"
/>
</scroll-view>
样式改动:给 .hot-category-wrapper 固定高度,让 HotCategoryBlock 的内部 scroll 有边界:
.hot-category-wrapper {
position: relative;
/* 100vh - header(208rpx) - banner(360rpx) - tabs(88rpx) = 可用 body 高度 */
height: calc(100vh - 208rpx - 360rpx - 88rpx);
}
2. HotCategoryBlock 内部改造 (frontend/pages/square/components/HotCategoryBlock.vue)
把 grid 区域(loading 骨架 / items-grid)包到一个新的内部 <scroll-view> 中。
模板改动:
<template>
<view class="hot-category-block">
<!-- Tab 栏(固定不滚)-->
<view class="ranking-tabs">
<!-- ... existing code ... -->
</view>
<!-- 网格区域:内部 scroll -->
<scroll-view
class="content-scroll"
scroll-y
:show-scrollbar="false"
:bounce="false"
>
<view v-if="loading" class="grid-skeleton">...</view>
<view v-else class="items-grid">...</view>
</scroll-view>
</view>
</template>
样式改动:
.hot-category-block {
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
}
.content-scroll {
flex: 1;
min-height: 0; /* flex 子项需要 min-height: 0 才能正确伸缩 */
overflow: hidden;
}
3. 切换 tab 时重置 scrollTop
在 square.vue 的 <script setup> 中加 watch:
import { ref, watch, onMounted, onUnmounted } from "vue";
// ... 现有代码 ...
watch(activeContentTab, () => {
// 切 tab 时把外层 scroll-view 滚回顶部
// 星河/星榜 时 scroll-y=false,但 scrollTop 残留可能导致显示异常
uni.pageScrollTo({ scrollTop: 0, duration: 0 });
});
备注:
uni.pageScrollTo是页面级 API,对 scroll-view 的 scrollTop 重置, 实际实现可改用ref绑定scroll-top属性并显式置 0。视具体平台支持调整。 如果运行时发现uni.pageScrollTo不生效,可改为:const scrollTop = ref(0); watch(activeContentTab, () => { scrollTop.value = 0; }); // <scroll-view :scroll-top="scrollTop" ...>
数据流 & 副作用
| Tab | 外层 scroll-y | onScroll 触发? | CreationGrid 分类标签 fixed |
|---|---|---|---|
| 星河 | false |
否 | 不相关(CreationGrid 不渲染) |
| 星榜 | false |
否 | 不相关 |
| 广场 | true |
是 | 正常 |
onScroll/handleScrollToLower内部已用creationGridRef.value?.updateScroll?.()可选链, 在creationGridRef为null时安全无副作用,无需修改onShow中activeContentTab.value = 'xinghe'重置行为保留Header/BottomNav/RankingModal/GuideOverlay都不受影响
错误处理
| 场景 | 处理 |
|---|---|
| 切到 星河/星榜 时 scrollTop 残留 | watch 重置 |
HotCategoryBlock 内部 scroll-view 在加载更多时 |
当前 HotCategoryBlock 内部没有 loadMore(数据固定 11 条),不需要处理;如未来需要,可参考 CreationGrid 的 scrolltolower 模式 |
top: -128rpx 在 scroll-y=false 时的视觉 |
保留现状,不调整;StarGalaxy 顶部 mask 透明渐变已设计为"上面有 banner 透出" |
测试要点
手动验证(无单元测试覆盖此 UI 行为):
- 星河:进入 星河 tab → 尝试上下/左右滑动 → 页面无任何滚动;StarGalaxy 完整可见部分铺满
- 星榜:进入 星榜 tab → 尝试滑动 banner / 顶部 → 顶部不滚;滑动 grid 卡片区域 → grid 区域独立滚
- 广场:进入 广场 tab → 整体页面可滚(与改造前完全一致)
- 切换:从 广场 滚动到中段 → 切到 星河 → 切回 广场 → 页面从顶部开始
- 横幅/分类 fixed:
CreationGrid的"分类标签切 fixed"在 广场 tab 仍正常 - 双击点赞/单击跳转:三个 tab 都正常
涉及文件
| 文件 | 改动 |
|---|---|
frontend/pages/square/square.vue |
scroll-view 加 :scroll-y 动态绑定;加 watch 重置 scrollTop;.hot-category-wrapper 加 height: calc(...) |
frontend/pages/square/components/HotCategoryBlock.vue |
grid 区域包到内部 scroll-view;加 .content-scroll 样式;改 .hot-category-block 为 flex 布局 |
不涉及
StarGalaxy任何文件(设计要求保留原状)CreationGrid任何文件(行为不变)BannerCarousel/ContentTabs/Header/BottomNav/RankingModal/GuideOverlay任何文件- 后端 API、store、composables