uni.createSelectorQuery().select(`#${id}`).boundingClientRect(data => { //目标位置节点 类或者 id
uni.createSelectorQuery().select(".idlePages").boundingClientRect((res) => { //最外层盒子节点类或者 id
uni.pageScrollTo({
duration: .3, //过渡时间
scrollTop: data.top - res.top - that.navBarHeight - 40, //到达距离顶部的top值
})
}).exec()
}).exec();
通过上边的核心代码,在数据加载时,记录每一个需要跳转的子项距最外层的高度,
然后利用uni的onPageScroll,判断当前滚动条的位置,与已经纪录好的子项高度进行比较,判断其在哪一个区间,来改变tab的位置;实现页面上下滚动监听;
再利用watch监听,监听tab的变化,判断其左滑还是右滑,来改变scroll-view距左边的距离,来实现顶部tab栏的左右的鉴定;
<template>
<view class="idlePages">
<my-fixedTop>
<view id="myNav">
<my-nav left-icon="back" :title="title" @click-left="back" shadow="none" :statusBar="true"></my-nav>
<view class="nav-top-bar" v-if="isShowTopBar">
<scroll-view scroll-x scroll-with-animation class="nav-top-bar-c" :scroll-left="scrollLeft">
<view v-for="(item, index) in tabList" :key="index" class="nav-bar-item" :class="[currentTab == index ? 'active' : '']"
@tap.stop="swichNav(index)">
<text class="tab-bar-title">{{ item.category_top_name }}</text>
</view>
</scroll-view>
</view>
</view>
</my-fixedTop>
<view class="idle-container" :style="{paddingTop:navBarHeight + 'px'}">
<view class="idle-top">
<image class="idle-bg" :src="imgUrl +'idle/idle-bg.png'" mode=""></image>
<view class="nav-bar">
<scroll-view scroll-x scroll-with-animation class="nav-bar-c" :scroll-left="scrollLeft">
<view v-for="(item, index) in tabList" :key="index" class="nav-bar-item" :class="[currentTab == index ? 'active' : '']"
@tap.stop="swichNav(index)">
<text class="tab-bar-title">{{ item.category_top_name }}</text>
</view>
</scroll-view>
</view>
</view>
<view class="idle-container-c" v-if="tabList.length" style="margin-top: -74rpx;">
<view class="idle-container-con" :id="item.id" v-for="(item,index) in tabList" :key="index">
<view class="idle-header-c" :class="index==0?'first':''">
<image :src="imgUrl+'idle/idle-icon-left.png'" mode="" class="idle-icon"></image>
<view class="idle-title">
{{item.category_top_name}}
</view>
<image :src="imgUrl+'idle/idle-icon-right.png'" mode="" class="idle-icon"></image>
</view>
<view class="idle-goods-list">
<view class="idle-goods-item" v-for="item2,index2 in item.product_list" :key="index2">
<view class="idle-goods-item-c">
<view class="goods-item-l">
<image class="goods-icon" :src="imgUrl+'idle/goods-icon1.png'" mode="" v-if="item2.show_order==1"></image>
<image class="goods-icon" :src="imgUrl+'idle/goods-icon2.png'" mode="" v-if="item2.show_order==2"></image>
<image class="goods-icon" :src="imgUrl+'idle/goods-icon3.png'" mode="" v-if="item2.show_order==3"></image>
<image class="goods-img" :src="item2.img" mode="aspectFill"></image>
</view>
<view class="goods-item-r">
<view class="good-item-title">
{{item2.template_name}}
</view>
<view class="good-item-brand">
{{item2.brand_name}}
</view>
<view class="good-item-price">
<view class="good-price-l">
<text class="price-title">行情价:</text>
<text class="price">¥{{item2.price}}</text>
</view>
<view class="good-price-r">
<text class="ranking-title">较昨日:</text>
<text class="ranking" :class="item2.diff_price_color=='r'?'r':'g'">{{item2.diff_price}}</text>
</view>
</view>
</view>
</view>
</view>
<view class="load-more-box" v-if="item.loadMore">
<view class="load-more" @tap.stop="loadMore(item,index)">
<text>展开更多</text>
<image :src="imgUrl+'idle/load_more.png'" mode=""></image>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
let that;
export default {
data() {
return {
title: "测试",
allPathUrl: this.$allPathUrl,
pathUrl: this.$pathUrl,
imgUrl: this.$imgUrl,
navBarHeight: this.$store.state.navBarHeight, //导航栏高度
scrollLeft: 0, //tab标题的滚动条位置
currentTab: 0,
activeH: 0,
isShowTopBar: false,
tabList: [],
activeTab: {},
jsonData: {
size: 6,
action: 'index',
},
}
},
watch: {
currentTab(newName, oldName) {
this.$nextTick(function() {
if (newName % 3 == 0 && newName !== 0) {
if (oldName < newName) {
this.scrollLeft = this.scrollLeft + 300;
} else {
this.scrollLeft = this.scrollLeft - 300;
}
}
})
}
},
onLoad() {
that = this;
this.loadInit();
},
methods: {
// 初始化函数
loadInit() {
this.$api
.getInfo(
'XXXXXX', this.jsonData,
''
)
.then(res => {
if (res.result == 'ok') {
this.tabList = res.rec_info;
this.tabList.forEach((ite, idx) => {
this.$set(ite, 'loadMore', true);
// 每个子项设置id名称;
this.$set(ite, 'id', `idle-header${idx}`);
// 记录每项的高度;
this.$nextTick(function() {
uni.createSelectorQuery().select(`#${ite.id}`).boundingClientRect(data => { //目标位置节点 类或者 id
uni.createSelectorQuery().select(".idlePages").boundingClientRect((res) => { //最外层盒子节点类或者 id
that.$set(ite, 'idT', data.top - res.top - that.navBarHeight - 40);
}).exec()
}).exec();
})
})
} else {
this.$utils.uniShowToast(res.info);
}
})
},
//展开更多
loadMore(item, index) {
var loadData = {
size: 6,
action: 'view_more',
category_top_id: item.category_top_id,
start: item.product_list.length,
}
this.$api
.getInfo(
'XXXXXX', loadData,
''
)
.then(res => {
if (res.result == 'ok') {
if (res.rec_info.length) {
this.$nextTick(function() {
this.tabList[index].product_list = this.tabList[index].product_list.concat(res.rec_info);
// 计算小于当前项的其它项高度;
setTimeout(function() {
that.getOtherTop(index);
}, 1500);
})
} else {
this.$nextTick(function() {
this.tabList[index].loadMore = false;
})
this.$utils.uniShowToast("没有更多了");
}
} else {
this.$utils.uniShowToast(res.info);
}
})
},
/**
* 返回上一页
*/
back() {
this.$utils.goBack();
},
// 选择tab下标实现锚点跳转
swichNav(index) {
this.currentTab = index;
let str = `idle-header${index}`;
this.goTabContainer(str, index);
},
// 锚点跳转
goTabContainer(id, index) {
uni.createSelectorQuery().select(`#${id}`).boundingClientRect(data => { //目标位置节点 类或者 id
uni.createSelectorQuery().select(".idlePages").boundingClientRect((res) => { //最外层盒子节点类或者 id
uni.pageScrollTo({
duration: .3, //过渡时间
scrollTop: data.top - res.top - that.navBarHeight - 40, //到达距离顶部的top值
})
}).exec()
}).exec();
},
//计算当前元素距页面顶部的高度
getOtherTop(index) {
// 循环计算除自身以外其它的子项
this.tabList.forEach((ite, idx) => {
if (idx > index) {
uni.createSelectorQuery().select(`#${this.tabList[idx].id}`).boundingClientRect(data => { //目标位置节点 类或者 id
uni.createSelectorQuery().select(".idlePages").boundingClientRect((res) => { //最外层盒子节点类或者 id
that.$nextTick(function() {
this.tabList[idx].idT = data.top - res.top - that.navBarHeight - 40;
})
}).exec()
}).exec();
}
})
},
},
onPageScroll(e) {
if (e.scrollTop > 350) {
this.isShowTopBar = true;
} else {
this.isShowTopBar = false;
}
// 生成高度区间数组
let arr2 = [];
this.tabList.forEach((ite, idx) => {
let arr = [];
arr.push(ite.idT)
arr2 = arr2.concat(arr);
})
// 控制高度区间
for (var i = 0; i < arr2.length; i++) {
if (e.scrollTop < (arr2[i + 1])) {
this.currentTab = i;
break;
}
}
},
}
</script>
<style lang="scss">
page {
background-color: #D47B57;
}
.idlePages {
.nav-top-bar {
width: 100%;
height: 80rpx;
background-color: #CE6D45;
.nav-top-bar-c {
width: 650rpx;
height: 80rpx;
margin: 0 auto;
white-space: nowrap;
.nav-bar-item {
height: 80rpx;
margin-right: 140upx;
color: #EBB69E;
font-size: 28rpx;
display: inline-block;
font-weight: 400;
line-height: 80rpx;
}
.nav-bar-item:last-child {
margin-right: 0rpx;
}
.nav-bar-item.active {
color: #FFFFFF;
font-weight: 500;
}
}
}
.idle-container {
padding-bottom: env(safe-area-inset-bottom);
.idle-top {
width: 750rpx;
height: 800rpx;
position: relative;
.idle-bg {
width: 750rpx;
height: 800rpx;
position: absolute;
top: 0;
left: 0;
z-index: -1;
}
.nav-bar {
width: 750rpx;
height: 80rpx;
position: absolute;
bottom: 80rpx;
left: 0rpx;
z-index: 0;
.nav-bar-c {
width: 650rpx;
height: 80rpx;
margin: 0 auto;
white-space: nowrap;
.nav-bar-item {
height: 80rpx;
margin-right: 140upx;
color: #EBB69E;
font-size: 28rpx;
display: inline-block;
font-weight: 400;
line-height: 80rpx;
}
.nav-bar-item:last-child {
margin-right: 0rpx;
}
.nav-bar-item.active {
color: #FFFFFF;
font-weight: 500;
}
}
}
.idle-header-top {
position: absolute;
left: 0;
bottom: 0;
}
}
.idle-header {
width: 750rpx;
height: 80rpx;
}
.idle-header-c {
width: 690rpx;
height: 80rpx;
margin: 0 auto;
margin-top: 30rpx;
display: flex;
align-items: center;
justify-content: center;
.idle-icon {
width: 36rpx;
height: 30rpx;
}
.idle-title {
font-size: 40rpx;
color: #fff;
font-weight: 500;
line-height: 80rpx;
margin: 0 20rpx;
}
}
.idle-header-c.first {
margin-top: 0rpx;
}
.idle-container-c {
width: 690rpx;
margin: 0 auto;
padding-bottom: 20rpx;
.idle-goods-list {
width: 100%;
.idle-goods-item {
width: 100%;
height: 260rpx;
margin-bottom: 20rpx;
background-color: #fff;
border: 4rpx;
position: relative;
.idle-goods-item-c {
width: 650rpx;
height: 220rpx;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
display: flex;
align-items: center;
justify-content: space-between;
.goods-item-l {
width: 240rpx;
height: 220rpx;
position: relative;
.goods-icon {
width: 44rpx;
height: 60rpx;
position: absolute;
top: -20rpx;
left: 0;
}
.goods-img {
width: 100%;
height: 100%;
// background-color: red;
}
}
.goods-item-r {
width: 389rpx;
height: 220rpx;
.good-item-title {
width: 100%;
height: 80rpx;
font-size: 28rpx;
font-weight: 400;
color: #333;
line-height: 42rpx;
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
}
.good-item-brand {
font-size: 25rpx;
color: #333;
line-height: 25rpx;
margin-top: 20rpx;
}
.good-item-hot {
margin-top: 20rpx;
width: 202rpx;
height: 32rpx;
background-color: #FFE1E0;
border-radius: 20rpx;
font-size: 22rpx;
font-weight: 400;
line-height: 32rpx;
color: #D33032;
position: relative;
.hot-icon {
width: 32rpx;
height: 32rpx;
position: absolute;
top: 0;
left: 0;
}
.hot-title {
margin-left: 40rpx;
}
}
.good-item-price {
width: 100%;
height: 40rpx;
margin-top: 55rpx;
display: flex;
align-items: center;
justify-content: space-between;
font-weight: 400;
.price-title {
font-size: 24rpx;
color: #666;
line-height: 24rpx;
}
.price {
line-height: 32rpx;
color: #F1982C;
}
.ranking-title {
font-size: 22rpx;
color: #999;
line-height: 22rpx;
}
.ranking {
font-size: 22rpx;
line-height: 22rpx;
}
.r {
color: #D63C3E;
}
.g {
color: #71BB31;
}
}
}
}
}
.load-more-box {
width: 100%;
height: 55rpx;
margin-top: 40rpx;
.load-more {
width: 208rpx;
height: 48rpx;
margin: 0 auto;
border: 1px solid #fff;
border-radius: 32rpx;
display: flex;
align-items: center;
justify-content: center;
text {
line-height: 48rpx;
font-size: 24rpx;
color: #fff;
}
image {
width: 14rpx;
height: 8rpx;
margin-left: 8rpx;
}
}
}
}
}
}
}
</style>