uniapp使用scroll-into-view实现锚点定位和滚动监听功能

功能介绍

1、点击左侧分类导航栏页面右侧区域滚动到对应的分类数据,通过scroll-into-view实现,

2、滚动右侧区域,滚动到哪一分类的的区域,左侧导航栏对应分类的导航变为选中状态,通过滚动监听实现。

页面截图

代码实现

html结构

<template>
	<view class="main">
		<scroll-view scroll-y="true" class="left-content">
			<view class="left-item" :class="{ 'activeItem': tabIndex == index }" v-for="(item,index) in leftData" :key="item.id" @click="clickLeftItem(index)">{{item.title}}</view>
		</scroll-view>
		<scroll-view scroll-y="true" class="right-content" :scroll-into-view="scrollId" scroll-with-animation @scroll="scrollEvt">
			<view class="right-item" v-for="(item,index) in rightData" :key="item.id" :id="'item'+index">
				<view class="title">
					{{item.title}}
				</view>
				<view class="content">
					<view class="content-item" v-for="itm in item.children" :key="itm.id">
						{{itm.text}}
					</view>
				</view>
			</view>
		</scroll-view>
	</view>
</template>

js

<script>
	export default {
		data() {
			return {
				tabIndex:0,
				scrollId:'',
				distanceList:[],
				timer:null,
				isLeftClick:false,
				leftData:[{
					title:'第一个',
					id:10001
				},
				{
					title:'第二个',
					id:10002
				},
				{
					title:'第三个',
					id:10003
				},
				{
					title:'第四个',
					id:10004
				},
				{
					title:'第五个',
					id:10005
				},
				{
					title:'第六个',
					id:10006
				}],
				rightData:[{
					id:'20001',
					title:'第一部分标题',
					children:[{
						id:'30001',
						text:'第一个子项'
					},
					{
						id:'30002',
						text:'第二个子项'
					},
					{
						id:'30003',
						text:'第三个子项'
					},
					{
						id:'30004',
						text:'第四个子项'
					}]
				},
				{
					id:'20002',
					title:'第二部分标题',
					children:[{
						id:'30005',
						text:'第一个子项'
					},
					{
						id:'30006',
						text:'第二个子项'
					},
					{
						id:'30007',
						text:'第三个子项'
					}]
				},
				{
					id:'20003',
					title:'第三部分标题',
					children:[{
						id:'30008',
						text:'第一个子项'
					},
					{
						id:'30009',
						text:'第二个子项'
					},
					{
						id:'30010',
						text:'第三个子项'
					},
					{
						id:'30011',
						text:'第四个子项'
					}]
				},
				{
					id:'20004',
					title:'第四部分标题',
					children:[{
						id:'30012',
						text:'第一个子项'
					},
					{
						id:'30013',
						text:'第二个子项'
					}]
				},
				{
					id:'20005',
					title:'第五部分标题',
					children:[{
						id:'300014',
						text:'第一个子项'
					},
					{
						id:'300015',
						text:'第二个子项'
					}]
				},
				{
					id:'20006',
					title:'第六部分标题',
					children:[{
						id:'300016',
						text:'第一个子项'
					},
					{
						id:'300017',
						text:'第二个子项'
					},
					{
						id:'300018',
						text:'第三个子项'
					},
					{
						id:'300019',
						text:'第四个子项'
					}]
				}]
			}
		},
		mounted(){
			setTimeout(()=>{
				this.getDistanceToTop();
			},500)
		},

		methods: {
			clickLeftItem(index){
				this.isLeftClick = true
				this.tabIndex = index
				this.scrollId = 'item'+index
			},
			getDistanceToTop() { //获取右侧各部分距离顶部的距离
				let that = this
				let selectorQuery = uni.createSelectorQuery().in(this);
			
				selectorQuery.selectAll('.right-item').boundingClientRect(function(rects) {
					rects.forEach(function(rect) {
						that.distanceList.push(rect.top)
					}) 
					console.log('that.distanceList',that.distanceList);
				}).exec()
			},
			
			// 元素滚动到顶部时,对应的左侧导航栏变为选中状态
			scrollEvt(e){
				// 点击左侧导航栏引起的滚动不做判断
				if(this.isLeftClick){
					this.isLeftClick = false
					return
				}
				// 防抖
				if(this.timer){
					clearTimeout(this.timer)
				}
				this.timer = setTimeout(()=>{
					let scrollTop = e.detail.scrollTop //滚动的高度
					// 找到位于顶部元素的索引,距离大于滚动高度的第一个元素的上一个元素就是此时位于顶部的元素
					let index = this.distanceList.findIndex(it=>{
						// 滚动条的位置大于元素距离顶部位置的距离时,说明元素已经滑过了顶部
						return (it > scrollTop)
					}) -1
					if(index == this.tabIndex) return
					this.tabIndex = index
				},200)
			}
		}
	}
</script>

css

<style lang="less" scoped>
	.main{
		display: flex;
		justify-content: space-between;
		width: 100vw;
		height: calc(100vh - 44px);
		.left-content{
			width: 250rpx;
			height: 100%;
			background-color: #E7E7E7;
			.left-item{
				width: 100%;
				height: 100rpx;
				text-align: center;
				line-height: 100rpx;
			}
		}
		.activeItem{
			background-color: #fff;
			color: skyblue;
		}
		.right-content{
			flex: 1;
			height: 100%;
			background-color: #f4f4f4;
		}
	}
	
	.content-item{
		width: 100%;
		height: 200rpx;
		background-color: aqua;
		margin-top: 20rpx;
	}
	.title{
		padding: 15px 0 0 10px;
	}
</style>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值