一、效果如下:

二、html模块
<view class="menu-content">
<view class="tab-wrap">
<view
:class="['tab', { active: activeTab === index }]"
v-for="(tab, index) in tabList"
:key="index"
@click="changeTab(index)"
>
{
{ tab }}
</view>
</view>
<scroll-view
scroll-y
@scrolltoupper="onScrolltoupper"
@scroll="onScroll"
:scroll-top="scrollTop"
>
<div class="menu-card" v-for="(item, index) in dataList" :key="index">
</div>
</scroll-view>
</view>
三、数据源
data() {
return {
dateList: [],
tabList: ["早餐", "午餐", "晚餐"],
activeTab: 0,
itemScrollTopArray: [],
scrollTop: 0,
};
},
四、方法
methods: {
getList() {
this.http({
...this.$miniapi.dishMenu.getCurMonthDetailDish,
showLoading: true,
}).then((res) => {
this.dataList = res.data;
this.getItemScrollTop();
});
},
getItemScrollTop() {
this.$nextTick(() => {
let selectorQuery = uni.createSelectorQuery().in(this);
selectorQuery
.selectAll(".menu-card")
.boundingClientRect((rects) => {
if (this.toolClass.isArrayAndNotEmpty(rects)) {
rects.forEach((item, index, array) => {
this.itemScrollTopArray.push(item.top - array[0].top);
});
}
})
.exec();
});
},
changeTab(index) {
this.activeTab = index;
this.scrollTop = this.itemScrollTopArray[index];
},
onScrolltoupper() {
this.scrolltop = 0;
},
onScroll(e) {
const currentScrollTop = e?.detail?.scrollTop;
if (!currentScrollTop) return;
const index = this.itemScrollTopArray.findIndex(
(scrollTop) => scrollTop >= currentScrollTop - 30
);
this.activeTab = index === -1 ? 0 : index;
},
},