问题: (1) 点击选项卡页面滚动到对应区域
(2) 滑动页面选项卡切换到对应Tab
(3) 选项卡切换与页面滚动双向联动
解决: (1) 通过
uni.createSelectorQuery().select('#id').boundingClientRect(data => {
console.log(data.top)
}).exec();获取所需节点距离页面顶部高度, 节点本身高度信息
(2) 通过
uni.createSelectorQuery().selectViewport('#id').scrollOffset(data => {
this.serviceDescScroll = data.scrollTop
}).exec(); 记录节点滑动距离
(3) 使用
uni.pageScrollTo({
scrollTop: 200, // 移动距离
duration:0 // 移动距离所需时间
}) 滚动页面到指定位置
(4) 在onReady中执行获取所需节点信息的方法
(5) 在onPageScroll中进行页面滑动切换选项卡的判断
(6) 在选项卡点击事件中处理页面滑动判断
<template>
<view class="animal-container">
<!-- 导航栏 -->
<my-custom id="my-custom" :bgImage="require('@/static/shop/shop-top2.png')">
<block slot="left">
<view class="status-left">
<view class="status-left-content" @click="backTo()">
<text class="cuIcon-back"></text>返回
</view>
</view>
</block>
<block slot="center">
<view class="search-form round">
<text class="cuIcon-search"></text>
<input :adjust-position="false" type="text" placeholder="搜索文章" confirm-type="search" @confirm="search" v-model="searchName"
@blur="checkInput"></input>
</view>
</block>
<block slot="right">
<view class="status-right">
</view>
</block>
</my-custom>
<view class="article-box2" v-show="isShow">
<view class="article-title2">
<view class="article-title-item" :class="index==TabCur?'text-jianbian':''" v-for="(item, index) in navTitle" :key="index" @click="tabChange(index)">
{{item.nav}}
</view>
</view>
</view>
<!-- 轮播图 -->
<view class="shop-image">
<swiper class="carousel box" :class="dotStyle?'square-dot':'round-dot'"
:indicator-dots="true" indicator-active-color="#55aaff" indicator-color="#f1f1f1"
:autoplay="true" interval="5000" duration="500">
<swiper-item v-for="n in 3" :key="n">
<view class="carousel-item">
<image src="../../static/activity/writingBg.png" mode=""></image>
</view>
</swiper-item>
</swiper>
</view>
<view class="article-box">
<view class="article-title" v-if="navShow">
<view class="article-title-item" :class="index==TabCur?'text-jianbian':''" v-for="(item, index) in navTitle" :key="index" @click="tabChange(index)">
{{item.nav}}
</view>
</view>
<view class="article-content">
<view class="service-desc">
<view class="service-desc-item" v-for="n in 60">
项目简介{{n}}
</view>
</view>
<view class="user-know">
<view class="user-know-item" v-for="n in 60">
用户须知{{n}}
</view>
</view>
<view class="comment-desc">
<view class="comment-desc-item" v-for="n in 60">
评论内容{{n}}
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
searchName: '',
dotStyle: true,
TabCur: 0,
statusHeight: 0, // 状态栏高度
navHeight: 0, // 选项卡 高度
navPageTop: 0, // 选项卡距离顶部高度
serviceDesc: 0, // 项目简介距离顶部高度
userKnow: 0, // 用户须知距离顶部高度
commentDesc: 0, // 评论内容距离顶部高度
navMobileTop: 0, //选项卡需要移动的距离
articleBoxHeight: 0, // 隐藏Nav选项卡距离顶部高度
serviceDescScroll: 0, // 项目简介距离顶部高度
userKnowScroll: 0, // 用户须知距离顶部高度
commentDescScroll: 0, // 评论内容距离顶部高度
lunboHeight: 0, // 轮播图高度
navShow: true,
isShow: false,
navTitle: [
{'nav': '项目简介', 'id': 0},
{'nav': '用户须知', 'id': 1},
{'nav': '评论内容', 'id': 2}
]
};
},
onLoad() {
},
onShow() {
},
onReady() {
this.getNodeScroll()
},
onPageScroll(e) {
// 隐藏Nav高度
uni.createSelectorQuery().select('.article-box2').boundingClientRect(data => {
this.articleBoxHeight = data.height
}).exec();
// Nav选项卡距离页面顶部高度
uni.createSelectorQuery().select('.article-title').boundingClientRect(data => {
this.navPageTop = data.top
}).exec();
// 轮播图高度
uni.createSelectorQuery().select('.shop-image').boundingClientRect(data => {
this.lunboHeight = data.height
}).exec();
// 项目简介距离顶部高度
uni.createSelectorQuery().selectViewport('.service-desc').scrollOffset(data => {
this.serviceDescScroll = data.scrollTop
}).exec();
// 用户须知距离顶部高度
uni.createSelectorQuery().selectViewport('.user-know').scrollOffset(data => {
this.userKnowScroll = data.scrollTop
}).exec();
// 评论内容距离顶部高度
uni.createSelectorQuery().selectViewport('.comment-desc').scrollOffset(data => {
this.commentDescScroll = data.scrollTop
}).exec();
if (e.scrollTop > this.lunboHeight) {
this.isShow = true
// 项目简介上移过程中距离当前可视窗口顶部高度
const serviceScrollTop = this.serviceDesc - this.serviceDescScroll
// 用户须知上移过程中距离当前可视窗口顶部高度
const userKnowScrollTop = this.userKnow - this.userKnowScroll
// 评论内容上移过程中距离当前可视窗口顶部高度
const commentDescScrollTop = this.commentDesc - this.commentDescScroll
// 状态栏加隐藏Nav选项卡高度
const allHeight1 = this.articleBoxHeight + this.statusHeight
// 状态栏加Nav选项卡高度
const allHeight2 = this.navHeight + this.statusHeight
if (serviceScrollTop < allHeight1 || serviceScrollTop == allHeight1) {
// 设置当前选项卡为项目简介
this.TabCur = 0
}
if (userKnowScrollTop < allHeight1 || userKnowScrollTop == allHeight1) {
// 设置当前选项卡为用户须知
this.TabCur = 1
}
if (commentDescScrollTop < allHeight1 || commentDescScrollTop == allHeight2) {
// 设置当前选项卡为评论内容
this.TabCur = 2
}
} else if(e.scrollTop < this.lunboHeight){
this.isShow = false
}
},
methods:{
// 返回上一级
backTo(){
uni.navigateBack({
delta:1
})
},
// 切换tab
tabChange(e) {
this.TabCur = e
this.navMobileTop = this.navPageTop - this.statusHeight
// 项目简介需要上移距离
const serviceMobileTop = this.serviceDesc - this.statusHeight - this.navHeight
// 用户须知需要上移距离
const userKnowMobileTop = this.userKnow - this.statusHeight - this.navHeight
// 评论内容需要上移距离
const commentMobileTop = this.commentDesc - this.statusHeight - this.navHeight
uni.pageScrollTo({
scrollTop: this.navMobileTop,
duration:0
})
this.isShow = true
if (e == 0){
uni.pageScrollTo({
scrollTop: serviceMobileTop,
duration:0
})
} else if (e == 1){
uni.pageScrollTo({
scrollTop: userKnowMobileTop,
duration:300
})
} else if(e == 2){
uni.pageScrollTo({
scrollTop: commentMobileTop,
duration:300
})
}
},
// 获取节点滚动信息
getNodeScroll(){
const query = uni.createSelectorQuery().in(this);
// 项目简介距离顶部高度
query.select('.service-desc').boundingClientRect(data => {
this.serviceDesc = data.top
}).exec();
// 用户须知距离顶部高度
query.select('.user-know').boundingClientRect(data => {
this.userKnow = data.top
}).exec();
// 评论内容距离顶部高度
query.select('.comment-desc').boundingClientRect(data => {
this.commentDesc = data.top
}).exec();
// Nav选项卡高度
query.select('.article-title').boundingClientRect(data => {
this.navHeight = data.height
}).exec();
// 状态栏高度
query.select('#my-custom').boundingClientRect(data => {
this.statusHeight = data.height
}).exec();
}
}
}
</script>
<style lang="scss">
.animal-container{
width: 100%;
background-color: #F1F1F1;
.status-left{
display: flex;
flex-direction: column;
.status-left-content{
display: flex;
justify-content: center;
font-size: 36rpx;
}
}
.status-right{
display: flex;
flex-direction: column;
.status-right-content{
display: flex;
justify-content: center;
image{
width: 40rpx;
height: 40rpx;
}
}
}
.shop-image{
width: 100%;
height: 360rpx;
padding-top: 0;
/* position: absolute;
top: 0;
left: 0; */
.carousel{
width: 100%;
height: 100%;
::v-deep .uni-swiper-wrapper{
.uni-swiper-dots{
bottom: 60rpx;
.uni-swiper-dot-active{
}
.uni-swiper-dot{
}
}
}
.carousel-item{
width: 100%;
height: 100%;
image{
width: 100%;
height: 100%;
}
}
}
}
.article-box2{
width: 100%;
position: fixed;
z-index: 999;
.article-title2{
width: 100%;
background-color: #FFFFFF;
display: flex;
justify-content: space-around;
.article-title-item{
font-size: 36rpx;
line-height: 80rpx;
}
}
}
.article-box{
width: 100%;
background-color: #1CBBB4;
.article-title{
width: 100%;
background-color: #FFFFFF;
display: flex;
justify-content: space-around;
.article-title-item{
font-size: 36rpx;
line-height: 80rpx;
}
}
.article-title-fixed{
position: fixed;
z-index: 999999;
/* top: 93px; */
left: 0;
}
.article-content{
width: 100%;
.service-desc{
width: 94%;
margin: 20rpx 3%;
background-color: #4399FC;
}
.user-know{
width: 94%;
margin: 20rpx 3%;
background-color: #ffaa7f;
}
.comment-desc{
width: 94%;
margin: 20rpx 3%;
background-color: #55ff7f;
}
}
}
}
</style>