uniapp中点击tab跳转到对应的位置,滚动到对应位置也会改变对应的tab高亮

<template>
	<view class="wrapper">
		<view class="header">
		</view>
		<view class="tabs" id="tabs" :style="{'display': showTabs ? 'block': 'none'}">
			<uv-tabs :current="currentTab" :list="tabs" @click="clickItem" lineColor='#1bb888'
				activeStyle="color:#1bb888;font-weight:bold" lineWidth='70px' itemStyle="width:140px;height:45px">
			</uv-tabs>
		</view>
		<view class="section">
			<view class="section">
				<view class="top" id="baseInfo">
					<view class="title">基本信息</view>
				</view>
				<view class="content content_progress">
					<view class="content_list">
						<view class="content_list_item" v-for="(item, index) of list" :key="index">
							<view class="content_list_item_label">
								{{ item.label }}
							</view>
						</view>
					</view>
				</view>
			</view>
		</view>
		<view class="section">
			<view class="section">
				<view class="top" id="company">
					<view class="title">公司信息</view>
				</view>
				<view class="content content_progress">
					<view class="content_list">
						<view class="content_list_item" v-for="(item, index) of 10" :key="index">
							<view class="content_list_item_label">
								{{ item }}
							</view>
						</view>
					</view>
				</view>
			</view>
		</view>
		<view class="section">
			<view class="section">
				<view class="top" id="money">
					<view class="title">财务信息</view>
				</view>
				<view class="content content_progress">
					<view class="content_list">
						<view class="content_list_item" v-for="(item, index) of 10" :key="index">
							<view class="content_list_item_label">
								{{ item }}
							</view>
						</view>
					</view>
				</view>
			</view>
		</view>
		<view class="section">
			<view class="section">
				<view class="top" id="process">
					<view class="title">运营状况</view>
				</view>
				<view class="content content_progress">
					<view class="content_list">
						<view class="content_list_item" v-for="(item, index) of 10" :key="index">
							<view class="content_list_item_label">
								{{ item }}
							</view>
						</view>
					</view>
				</view>
			</view>
		</view>
		<view class="section">
			<view class="section">
				<view class="top" id="layer">
					<view class="title">法务部门1</view>
				</view>
				<view class="content content_progress">
					<view class="content_list">
						<view class="content_list_item" v-for="(item, index) of 2" :key="index">
							<view class="content_list_item_label">
								{{ item }}
							</view>
						</view>
					</view>
				</view>
			</view>
		</view>
		<view class="section">
			<view class="section">
				<view class="top" id="people">
					<view class="title">人事部门2</view>
				</view>
				<view class="content content_progress">
					<view class="content_list">
						<view class="content_list_item" v-for="(item, index) of 2" :key="index">
							<view class="content_list_item_label">
								{{ item }}
							</view>
						</view>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script setup>
	import {
		onLoad,
		onShow,
		onPageScroll
	} from '@dcloudio/uni-app'
	import {
		nextTick,
		ref
	} from 'vue'

	const showTabs = ref(false) // 默认吸顶的tab不显示
	const currentTab = ref(-1) // 由于初始化的uview的代码有bug,所以默认是-1,在第一次显示的时候,设置0,自动复位,防止错误
	const list = ref([{
			label: '年龄',
			value: '19'
		},
		{
			label: '性别',
			value: '男'
		}
	])
	const distanceArr = ref([]) // 每一个ID对应的scrollTop值
	const tabs = ref([{

			id: '#baseInfo',
			name: '基本信息',
		},
		{
			id: '#company',
			name: '公司信息',
		},
		{
			id: '#money',
			name: '财务信息',
		},
		{
			id: '#process',
			name: '运营状况',
		},
		{
			id: '#layer',
			name: '法务部门',
		},
		{
			id: '#people',
			name: '人事部门',
		}
	])
	const isTabChange = ref(false) // 防止在点击tab的时候,页面的滚动导致重复计算、抖动问题


	// 监听页面滚动
	onPageScroll((event) => {
		if (isTabChange.value) {
			return
		}
		const {
			scrollTop
		} = event;
		const skewY = 55 // 偏移量,由于吸顶的tab、头部的显示信息也有高度,素以做了偏移量
		if (scrollTop >= skewY) {
			if (!showTabs.value && currentTab.value <= 0) { // 在未显示tab并且 currentTab <= 0时,防止uview ui抖动bug,设置默认复位值
				currentTab.value = 0
			}
			showTabs.value = true

			nextTick(() => {
				// console.log(distanceArr.value);
				const length = distanceArr.value.length
				const index = distanceArr.value.findIndex(el => el - skewY - scrollTop > 0)
				// 当index  == -1 的时候,实际当前滚动的距离超出了最大值,也就是在最后一个tab显示的内容
				// 当index > 0 的时候,说明能在当前的scrollTop值找到,即index的前一位
				currentTab.value = index > 0 ? index - 1 : length - 1
				// console.log(currentTab.value);
			})
		} else {
			showTabs.value = false
		}
	})

	onShow(() => {
		nextTick(() => {

			getDistanceArr()
		})

	})

	// 获取所有元素在当前页面所处的位置信息
	const getDistanceArr = () => {
		tabs.value.map(el => {
			uni.createSelectorQuery().select(el.id).boundingClientRect(data => {
				// 获取当前ID距离顶部的top值
				
				distanceArr.value.push(data.top)
			}).exec()
		})
		console.log(distanceArr.value);
	}
	const clickItem = (item, index) => {
		isTabChange.value = true
		// 方法一 简单一点直接跳转到id对应的位置 
		nextTick(() => {
			uni.pageScrollTo({
				selector: item.id,
				duration: 300,
				complete: function() {
					const timer = setTimeout(() => {
						isTabChange.value = false // 关闭
						clearTimeout(timer)
					}, 500) // 解决ios和安卓、鸿蒙系统兼容性问题
				}
			});
		})
		// 方法二  计算对应位置的top跳转
		// this.$nextTick 保证当前isTabChange 为true后执行代码
		// 避免在istabChange变为true的时候,执行代码,监听事件还是会继续执行重新计算currenTab值
		// nextTick(() => {
		// 	currentTab.value = item.index
		// 	uni.createSelectorQuery().select(item.id).boundingClientRect(data => {
		// 		uni.createSelectorQuery().select('.wrapper').boundingClientRect(res => {
		// 			const scrollTop = data.top - res.top // 获取差值
		// 			const skewY = 50 // 偏移
		// 			// 页面开始进行滚动到目标位置
		// 			uni.pageScrollTo({
		// 				scrollTop: scrollTop > 0 ? scrollTop - skewY : scrollTop + skewY,
		// 				duration: 300,
		// 				complete: function() {
		// 					const timer = setTimeout(() => {
		// 						isTabChange.value = false // 关闭
		// 						clearTimeout(timer)
		// 					}, 500) // 解决ios和安卓、鸿蒙系统兼容性问题
		// 				}
		// 			});
		// 		}).exec()
		// 	}).exec()
		// })
	}
</script>

<style scoped lang="scss">
	.wrapper {
		background: white;
		min-height: 100vh;

		.header {
			height: 100rpx;
			background: orange;

			.bg {
				width: 100vw;
				height: 200rpx;
			}
		}

		.tabs {
			position: sticky;
			z-index: 970;
			top: 0px;
			background-color: #fff;
			width: 100vw;

			.tabsStyle {
				box-shadow: 0 2rpx 6rpx 0 rgba(153, 153, 153, 0.2);

				::v-deep {
					.u-tabs {
						box-shadow: 0px 4px 6px 0 rgba(153, 153, 153, 0.2);
					}
				}
			}
		}

		.section {
			width: 100%;
			padding: 0 30rpx;
			box-sizing: border-box;

			.top {
				width: 100%;
				display: flex;
				flex-direction: row;
				flex-wrap: nowrap;
				justify-content: space-between;

				.title {
					font-size: 40rpx;
					font-family: PingFangSC-Semibold, PingFang SC;
					font-weight: 600;
					color: #333333;
					margin-left: 30rpx;
					position: relative;

					&::before {
						position: absolute;
						content: '';
						left: -30rpx;
						width: 14rpx;
						height: 77%;
						top: 10%;
						border-radius: 14rpx;
						background: #00bb84;
					}
				}

				.right {
					position: relative;
					display: flex;
					justify-content: center;
					align-items: center;
					width: 20rpx;

					.dots {
						display: flex;
						flex-direction: column;
						justify-content: space-between;
						height: 33rpx;
						width: 26rpx;
						align-items: center;
						padding: 10rpx 20rpx;
						margin-right: 4rpx;

						.dot {
							width: 9rpx;
							height: 9rpx;
							background: #000000;
							border-radius: 50%;
						}
					}

					.more_menu {
						position: absolute;
						top: 70rpx;
						right: 0;
						z-index: 99;
						background: white;
						padding: 0 20rpx;
						box-shadow: 0px 3px 5px 0px rgba(0, 0, 0, 0.2);
						border-radius: 4rpx;

						.more_menu_item {
							font-size: 30rpx;
							padding: 24rpx 180rpx 24rpx 16rpx;
							white-space: nowrap;
						}

						.more_menu_item:not(:last-child) {
							border-bottom: 1rpx solid #dddddd;
						}
					}
				}
			}

			.content {
				background: #f8f8f9;
				border-radius: 30rpx;
				padding: 32rpx;
				margin-top: 20rpx;

				&_top {
					display: flex;
					flex-direction: row;
					flex-wrap: nowrap;
					margin-bottom: 24rpx;

					&_name {
						font-weight: bold;
						color: #333333;
						font-size: 32rpx;
					}

					&_ismySelf {
						background: #eeeeee;
						font-weight: 500;
						color: #999999;
						font-size: 24rpx;
						margin-left: 12rpx;
						padding: 6rpx 18rpx;
						border-radius: 10rpx;
					}
				}

				&_Info {
					display: flex;
					flex-direction: row;
					flex-wrap: nowrap;
					justify-content: space-between;
					padding-bottom: 20rpx;
					margin-top: 20rpx;

					&_item {
						display: flex;
						flex-direction: column;
						flex: 1;
						text-align: center;

						&_label {
							text-align: center;
							font-size: 24rpx;
							font-weight: 300;
							color: #999999;
						}

						&_value {
							font-size: 34rpx;
							font-weight: bold;
							color: #333333;
							margin-top: 14rpx;
						}
					}

					&_item:not(:last-child) {
						position: relative;

						&::after {
							position: absolute;
							content: '';
							width: 1rpx;
							height: 70rpx;
							top: 20rpx;
							right: 0;
							background: #d8d8d8;
						}
					}
				}

				&_Info:not(:last-child) {
					border-bottom: 1rpx solid #d8d8d8;
				}

				&_remark {
					font-weight: 400;
					color: #333333;
					font-size: 24rpx;
					padding-top: 20rpx;
					text-align: justify;
					min-height: 40rpx;
				}

				&_list {
					&_item {
						display: flex;
						flex-direction: row;
						flex-wrap: nowrap;
						padding: 20rpx 0;
						border-bottom: 1rpx solid #d8d8d8;

						&_label {
							font-size: 30rpx;
							font-weight: 500;
							color: #00bb84;
							white-space: nowrap;
							width: 180rpx;
							display: flex;
							flex-direction: column;
							justify-content: center;
							align-items: center;
						}

						&_value {
							font-size: 30rpx;
							font-weight: 400;
							color: #666666;
							flex: 1;
							margin-left: 40rpx;
							align-self: center;
							word-break: break-all;
							text-align: justify;
						}
					}

					&_empty {
						height: 180rpx;
						background: #f8f8f9;
						border-radius: 10rpx;
						display: flex;
						flex-direction: column;
						justify-content: center;
						align-items: center;

						&_tip {
							font-size: 20rpx;
							font-weight: 400;
							color: #999999;
							margin-top: 20rpx;
							line-height: 30rpx;
						}

						image {
							width: 64rpx;
							height: 50rpx;
						}
					}

					&_emptyResult {
						height: 240rpx;

						image {
							width: 166rpx;
							height: 166rpx;
						}

						&_tip {
							margin-top: 0;
						}
					}
				}

				&.reset {
					padding: 0;
				}

				&_reportList {
					display: grid;
					grid-template-columns: repeat(4, 1fr);
					grid-gap: 20rpx;

					&_pack {
						width: 100%;
						height: calc(25vw - 30rpx);
						border-radius: 20rpx;
					}

					&_addImage {
						width: 100%;
						height: calc(25vw - 30rpx);
						background: #f8f8f9;
						border-radius: 20rpx;
						// border: 2rpx dashed #bbbbbb;
						display: flex;
						flex-direction: column;
						justify-content: center;
						align-items: center;

						&_icon {
							width: 60rpx;
							height: 48rpx;
						}

						&_tip {
							font-size: 20rpx;
							font-weight: 400;
							line-height: 30rpx;
							color: #999999;
							margin-top: 14rpx;
						}
					}
				}
			}

			.content_progress {
				background: initial;
				padding: 0 30rpx;
			}

			.content_result {
				background: initial;
				font-size: 30rpx;
				font-weight: 400;
				color: #666666;
				word-wrap: break-word;
				word-break: normal;
				line-height: 60rpx;
				letter-spacing: 2rpx;
				text-align: justify;
			}

			.content_report {
				background: initial;
				padding: 12rpx 0;
			}
		}

		.section:not(:first-child) {
			margin-top: 20rpx;
		}
	}
</style>


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值