uiapp tab栏切换时内容自动滚动到相对应的位置

业务需求

1,tab栏的项是动态的,可横向滚动,

2,点击tab栏时,内容自动滚到相对应的位置

3,滚动内容时,对应的内容要高亮对应的tab

视频展示

下面介绍代码(都带有注释就不一一介绍)

<template>
	
		<scroll-view class="tab-scroll-sticky" id="tabs" scroll-y="true" @scroll="tabScoll" :scroll-top="scrollInto">
			<view class="directSignature">
				<view id="scrollTop">
					<!-- 顶部信息 -->
					<view class="directSignature-top">
						头部
					</view>
				</view>
				<view class="scroll-content">
					<view :class="[barshow?'scroll-tab-fixed':'scroll-tab-static']" :style="{top:barshow?'0':'0'}">
						<scroll-view scroll-x="true" :scroll-left="scrollLeft"
							style="background-color: #fff;">
							<view class="scroll-tab">
								<view class="scroll-tab-list" v-for="(item,index) in tabList"
									:style="{color:activeTab == index?activeColor:'#8895ac'}" @click="changeTab(index)"
									:id="'tabs'+index" :key="index">
									<text class="scroll-tab-list-text">{{item.text}}</text>
									<view v-if="activeTab == index" class="scroll-tab-list-text-line"
										:style="[tabBarStyle]">
									</view>
								</view>
							</view>
						</scroll-view>
					</view>
				</view>
				<view class="scroll-warp" ref="scroll">
					<view class="scroll-warp-list" :ref="'wrap'+index" v-for="(item,index) in tabList" :key="">
						<view class="directSignature-conten">
							<!-- tab栏标签 -->
							<view class="directSignature-tabstatus" :id="'wrap'+index">
								{{item.text}}
							</view>

							<!-- 检查项目 -->
							<view class="directSignature-checkProject">
								<!-- 登记事项检查 -->
									<view class="directSignature-checkProject-title" v-for="(i,index) in item.des" :key="index">
										{{item.text}}---内容{{index}}
									</view>
							</view>

						</view>
					</view>

				</view>
			</view>
		</scroll-view>

</template>

<script>
	export default {
		name: 'tab-scroll-sticky',
		data() {
			return {
				barshow: false, //是否显示吸顶
				tabTop: 0, //距离顶部的距离
				activeTab: 0, //高亮tal栏的项
				scrollInto: 0, //scrllo-view y轴滚动的高度
				scrollLeft: 0, //tab栏X轴的滚动的距离
				tabBarStyle: {}, //tab栏底部行线的样式
				warpTop: [], //每一个内容开始的高度(距离顶部的高度)
				// 内容
				tabList: [
					{id:1,text:"第1111",des:20},
					{id:2,text:"第22",des:20},
					{id:3,text:"第333",des:20},
					{id:4,text:"第44",des:20},
					{id:5,text:"第55555",des:20},
					{id:6,text:"第6666",des:20},
				],
				activeColor: '#ff0000',//线的颜色
			};
		},
		computed: {},
		onLoad(option) {
			this.resetHight()

		},
		watch: {},
		methods: {
			//数据装载完成后重新获取高度
			resetHight() {
				this.$nextTick(async function() {
					let rect = await this.GetRect("#scrollTop"); //获取id为scrollTop的div的节点信息
					this.tabTop = rect.height; 
					this._getTabRect(0); //获取tab栏高亮第一位的信息
					this.barInit(); //获取节点的高度
				});
			},

			//获取节点信息
			GetRect(selector) {
				return new Promise((resolve, reject) => {
					let view = uni.createSelectorQuery().in(this)
					view.select(selector).boundingClientRect(rect => {
						resolve(rect)
					}).exec();
				})
			},
			//获取节点距离顶部距离
			barInit: async function(index) {
				this.scrollInto = 0 //初始值位0
				let navTargetTop = [];
				let navTargetTop1 = [];
				// 遍历通过ref获取对应没有个内容开始的高度
				for (let i = 0; i < this.tabList.length; i++) {
					var top = this.$refs['wrap' + i][0].$el.offsetTop
					navTargetTop.push(parseInt(top))
			
				}
				// 最后把每一项内容开始节点的高度数组赋值给this.warpTop
				this.warpTop = navTargetTop;
			},
			//tab切换
			changeTab(e) {
				var that = this
				this.activeTab = e;
				this.$nextTick(function() {
					that._getTabRect(that.activeTab); //页面点击切换的时候,重新设置tab栏的信息参数
					if (e == 0) {
						that.scrollInto = that.warpTop[e] - 44;
					} else {
						that.scrollInto = that.warpTop[e] - 93;
					}
				})
			},
			//获取一个tab宽度
			async _getTabRect(itemIndex) {
				// 获取tab栏的信息
				let rect = await this.GetRect("#tabs" + itemIndex);
				let rect1 = await this.GetRect("#tabs" + itemIndex + ">.scroll-tab-list-text");
				let width = (rect1.width * 0.67);
				if (itemIndex == this.activeTab) {
					this.scrollLeft = rect.left //向做滚动的距离
				}
				this.tabBarStyle = {
					width: width + 'px',
					background: this.activeColor,
				}
			},
			//Y轴scroll滚动
			async tabScoll(e) {
			
				let scrollTop = e.detail.scrollTop; //获取滚动的高度
				let rect = await this.GetRect("#scrollTop"); //获取页面信息
				// 第一次滚动时,tabTop=0
				if (this.tabTop == 0) {
					let rect = await this.GetRect("#scrollTop");
					this.tabTop = rect.height; //页面没有距离顶部的距离
				}
				// this.tabTop = 0 显示置顶
				this.barshow = scrollTop >= this.tabTop ? true : false;
				let scrollTop1 = scrollTop;
				// 循环遍历所有内容开始节点的高度数组
				for (var i = 0; i < this.warpTop.length; i++) {
					// 滚动的高度scrollTop1 小于this.warpTop[0],
					if (scrollTop1 <= this.warpTop[0]) {
						this.activeTab = 0;
						this.scrollInto = this.warpTop[0] - 44  //y轴滚动回this.warpTop[0]第一个节点的位置
						this._getTabRect(0);
					} else if (scrollTop1 > this.warpTop[this.warpTop.length - 1] - 93) {
						// 如果大于最后一位
						this.activeTab = this.warpTop.length - 1;
						this.scrollInto = this.warpTop[this.warpTop.length - 1]
						this._getTabRect(this.warpTop.length - 1);
					} else {
						// 其它,同理
						if (scrollTop1 > this.warpTop[i] - 93 && scrollTop1 < this.warpTop[i + 1] - 93) {
							this.scrollInto = scrollTop1
							this.activeTab = i;
							this._getTabRect(i);
						}
					}
				}

			},
		}
	};
</script>

<style lang="scss" scoped>
	uni-page-body{
		height: 100%;
		overflow: hidden;
	}
	.tab-scroll-sticky{
		height: 100%;
	}
	.flexRowCc {
		display: flex;
		flex-direction: row;
		align-items: center;
	}

	.scroll-content {
		position: relative;
		::-webkit-scrollbar {
			display: none;
			width: 0 !important;
			height: 0 !important;
			-webkit-appearance: none;
			background: transparent;
			color: transparent;
		}

		.scroll-tab {
			@extend .flexRowCc;
			justify-content: space-between;
			width: 100%;
			height: 44px;
			box-sizing: border-box;
			border-top: 1px solid #F1F1F1;
			border-bottom: 1px solid #F1F1F1;
			background: #FFFFFF;
			position: relative;
			z-index: 999;
			// overflow-x: auto;

			&-static {
				position: relative !important;
			}

			&-fixed {
				position: fixed;
				top: 0px;
				left: 0;
				width: 100%;
				z-index: 9999;
			}

			&-list {
				text-align: center;
				font-size: 24upx;
				color: #2266BC;
				flex: 1 1 auto;
				padding: 0 10upx;
				position: relative;

				&-text {
					display: inline-block;

					&-line {
						position: absolute;
						height: 4upx;
						transform: translateX(-50%);
						left: 50%;
						border-radius: 16upx;
						transition-duration: .5s;
						margin-top: 4rpx;
					}
				}
			}
		}
	}

	.scroll-warp {
		height: 100vh;
		padding-bottom: 200upx;
		// margin-bottom: 200upx;
	}

	// ---------------------------------------------
	.directSignature {
		&-top {
			width: 750upx;
			background: #f3c55c;
			height: 500upx;
			padding: 21upx;
		}
		&-tabstatus{
			background-image: linear-gradient(to left, #f97e36, #f3c55c);
			padding:10upx 30upx;
			display: inline-block;
			margin: 20upx 0;
			color: #FFFFFF;
			border-radius: 0 30upx 30upx 0;
		}
		&-checkProject {
			padding: 0 20upx;
		}
	}

	// 检查项目
	.directSignature-checkProject {
			&-title {
				color: #2266bc;
				font-size: 30upx;
				font-weight: 550;
				// background-image: linear-gradient(to bottom, #e3edf9, #fff);
				padding: 20upx;
				border-radius: 15upx;
				border-bottom: 3upx solid #eff5fb;
				white-space: 4upx;
				margin-bottom: 7upx;
				background-color:  #e3edf9;
			}
		
	}

</style>

都看这里了,点个赞再走呗

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值