uni-app选项卡内容区联动(适用商品详情页面等类似页面)

 问题: (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>

上一篇:uni-app跨平台框架介绍和快速入门


下一篇:UNI-APP获取当前位置,出现getLocation:fail [geolocation:7]错误的问题解决