template
<view class="sticky-container u-m-b-20" :class="{ 'sticky-container--hidden': isNavHidden }" :style="{ transform: isNavHidden ? `translateY(-${stickyContainerHeight}rpx)` : 'translateY(0)' }">
<ld-custom-tabs
class="shop-type-tabs"
:list="shopTypeTabs"
:current="activeShopTab"
@change="handleShopTabChange"
/>
</view>
<!-- 筛选条件:累计直推奖励、上月直推奖励、本月直推奖励 -->
<view class="filter-tabs-sticky" :class="{ 'filter-tabs-sticky--hidden': isNavHidden }" :style="{ top: stickyContainerHeight + 'rpx', transform: isNavHidden ? `translateY(-${stickyContainerHeight}rpx)` : 'translateY(0)' }">
<ld-filter-tabs
class="filter-tabs"
:list="filterTabs"
:current="activeFilterIndex"
:item-style="{ backgroundColor: '#fff', border: '1rpx solid #e5e5e5' }"
@change="handleFilterChange"
@reclick="handleFilterReclick"
/>
</view>
data
loading: false,
// sticky-container 的高度,用于设置 filter-tabs-sticky 的 top 值
stickyContainerHeight: 0, // 默认值 0rpx
// filter-tabs-sticky 距离顶部的距离(rpx)
filterTabsStickyTop: 0,
// 是否隐藏导航(向上移动)
isNavHidden: false,
// 上次滚动位置,用于判断滚动方向
lastScrollTop: 0
onReady() {
this.$nextTick(() => {
this.updateFilterTabsStickyPosition()
})
},
onPageScroll(e) {
this.handlePageScroll(e.scrollTop || 0)
},
methods
// 查询元素尺寸信息
queryRect(selector) {
return new Promise(resolve => {
uni.createSelectorQuery()
.in(this)
.select(selector)
.boundingClientRect(rect => {
resolve(rect)
})
.exec()
})
},
// 更新 filter-tabs-sticky 的 top 值
async updateFilterTabsStickyPosition() {
const systemInfo = uni.getSystemInfoSync()
const pxToRpxRatio = 750 / systemInfo.windowWidth
// 获取 sticky-container 的高度
const stickyRect = await this.queryRect('.sticky-container')
if (stickyRect && stickyRect.height) {
this.stickyContainerHeight = stickyRect.height * pxToRpxRatio
}
// 获取 filter-tabs-sticky 距离顶部的距离
// 在 onReady 时,页面应该还没有滚动,所以 top 就是相对于页面顶部的位置
const filterTabsRect = await this.queryRect('.filter-tabs-sticky')
if (filterTabsRect && filterTabsRect.top !== undefined) {
// top 是相对于视口的位置,在初始状态下(scrollTop = 0)就是相对于页面顶部的位置
this.filterTabsStickyTop = filterTabsRect.top * pxToRpxRatio
}
},
// 处理页面滚动
handlePageScroll(scrollTop) {
if (!this.stickyContainerHeight || !this.filterTabsStickyTop) return
// 将 scrollTop (px) 转换为 rpx
const systemInfo = uni.getSystemInfoSync()
const pxToRpxRatio = 750 / systemInfo.windowWidth
const scrollTopRpx = scrollTop * pxToRpxRatio
// 计算滚动阈值:filter-tabs-sticky 距离顶部的距离 - stickyContainerHeight
const threshold = this.filterTabsStickyTop - this.stickyContainerHeight
// 判断滚动方向
const isScrollingUp = scrollTop > this.lastScrollTop
const isScrollingDown = scrollTop < this.lastScrollTop
// 更新上次滚动位置
this.lastScrollTop = scrollTop
// 判断是否需要隐藏导航
if (scrollTopRpx >= threshold) {
// 超过阈值,根据滚动方向决定是否隐藏
if (isScrollingUp) {
// 向上滚动,隐藏导航
this.isNavHidden = true
} else if (isScrollingDown) {
// 向下滚动,显示导航
this.isNavHidden = false
}
// 如果滚动方向不变,保持当前状态
} else {
// 未超过阈值,显示导航
this.isNavHidden = false
}
}
},
css
.sticky-container {
position: sticky;
top: 0;
left: 0;
right: 0;
z-index: 10;
background-color: #f5f6fa;
padding: 12rpx 0;
margin: 0 -24rpx 16rpx;
transition: transform 0.3s ease-out;
}
.filter-tabs-sticky {
position: sticky;
left: 0;
z-index: 9;
background-color: #f5f6fa;
padding: 12rpx 0;
margin: 0 -24rpx 16rpx;
transition: transform 0.3s ease-out;
}