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

1.html代码:

<template>
	<view class="classicsBox">
		<scroll-view class="classics-left" scroll-y="true" scroll-with-animation :scroll-into-view="clickId">
			<view v-for="(item,index) in contentData" :key="item.id" :id="item.id" class="classics-left-item" :class="picked==index?'checkedStyle':''" @click="selectActiveEvt(item)">
				{{item.title}}
			</view>
		</scroll-view>
		<!-- :scroll-top="scrollRightTop" -->
		<scroll-view scroll-y="true"  :scroll-into-view="clickId" :scroll-anchoring="true" scroll-with-animation class="classics-right" @scroll="scrollEvt">
			<view class="classics-right-item" v-for="item in contentData" :key="item.id" :id="item.id">
				<view class="title">
					{{item.title}}
				</view>
				<view class="item-box" v-for="it in item.content">
					<img class="item-box-left" :src="it.img" alt="">
					<view class="item-box-right">
						<view class="item-box-right-name">
							{{it.name}}
						</view>
						<view class="item-box-right-describe">
							{{it.desc}}
						</view>
						<view class="item-box-right-buy">
							<view class="item-box-right-price">
								¥{{it.price}}
							</view>
							<view class="item-box-right-pick">
								选规格
							</view>
						</view>
					</view>
				</view>
			</view>
		</scroll-view>
	</view>
</template>

2.script代码

<script>
	export default {
		components: {},
		data() {
			return {
				contentData:[{
						id:'tab1',
						title:'热销专区',
						content:[
							{id:101,img:'static/rexiao1.png',name:'郁金香',desc:'花语',price:'99',},
							{id:102,img:'static/rexiao2.png',name:'郁金香',desc:'花语',price:'99',},
						]
					},
					{
						id:'tab2',
						title:'生日鲜花',
						content:[
							{id:201,img:'static/shengri1.png',name:'郁金香',desc:'花语',price:'99',},
							{id:202,img:'static/shengri2.png',name:'郁金香',desc:'花语',price:'99',},
						]
					},......],//列表数据
				clickId:'tab1', //点击选项的id
				picked:0, // 左侧选中选项的index
				nowRightIndex:0, // 右边当前滚动的index
				itemArr:[], //用于存放右侧item位置数据
				scrollRightTop:0,
				timer:null,
			}
		},
		
		methods: {
			// 左侧切换点击事件
			selectActiveEvt(e) {
				this.clickId = e.id;
				this.picked = this.contentData.findIndex(it=>it.id==e.id);
			},
			scrollEvt(e){
				// 防抖
				if(this.timer){
					clearTimeout(this.timer);
				}
				this.timer = setTimeout(()=>{
					this.nowRightIndex =  this.itemArr.findLastIndex(it=>e.detail.scrollTop>=(it.bottom-228))+1; //判断当前顶部是处于哪个item,获取当前item的index
					if(this.nowRightIndex==-1) this.nowRightIndex=0;
					if(this.nowRightIndex==this.picked) return;
					this.clickId = this.contentData[this.nowRightIndex].id;
					this.picked = this.nowRightIndex;
				},500);
			},
			// 计算右侧每个item到顶部的距离,存放到数组
			getItemDistence(){
				new Promise(resolve=>{
					let selectQuery = uni.createSelectorQuery().in(this);
					selectQuery.selectAll('.classics-right-item').boundingClientRect(rect=>{
						if(!rect.length){
							setTimeout(()=>{
								this.getItemDistence();
							},10);
							return;
						}
						rect.forEach(it=>{
							this.itemArr.push(it); // 这里获取到的数据是每个item距离页面顶部的数据,以及每个item的自身数据
							resolve();
						})
					}).exec()
				})
			},
		},
		mounted(){
			// 设置一个延时,确保所有dom和样式加载完成,否则拿到的数据可能有误
			setTimeout(()=>{
				this.getItemDistence();
			},500)
			
		},
	}
</script>

 3.css样式

.classicsBox{
		box-sizing: border-box;
		width: 100%;
		height: 100%;
		display: flex;
		padding-top: 8px;
	}
	.classics-left{
		width: 25%;
		height: 100%;
		box-sizing: border-box;
		padding-right: 6px;
		/* overflow-y: auto; */
	}
	.classics-left-item{
		height: 60px;
		box-sizing: border-box;
		text-align: center;
		line-height: 60px;
		color: black;
		font-weight: 600;
		font-size: 14px;
	}
	.classics-left-item:last-child{
		border: none;
	}
	.classics-right{
		background-color: #fff;
		width: 75%;
		box-sizing: border-box;
		/* overflow-y: auto; */
	}
	.classics-right-item{
		width: 100%;
		box-sizing: border-box;
	}
	.title{
		height: 50px;
		line-height: 50px;
		font-weight: 600;
		font-size: 14px;
		background: url('../../../static/itembackg.png') center center no-repeat ;
		background-size: 100%;
		box-sizing: border-box;
		padding-left: 10px;
		color: #87ff07;
		font-family: 'Courier New', Courier, monospace;
		/* -webkit-text-stroke: 1px #ff55ff; */
	}
	.item-box{
		display: flex;
		width: 100%;
		box-sizing: border-box;
		padding-bottom: 20px;
		padding-left: 10px;
	}
	.item-box-left{
		width: 90px;
		height: 90px;
		background-color: #fafafa;
		border-radius: 8px;
		box-sizing: border-box;
	}
	.item-box-right{
		width: calc(100% - 102px);
		box-sizing: border-box;
		padding-left: 12px;
		position: relative;
		box-sizing: border-box;
		background-color: #fff;
		
	}
	.item-box-right-name,.item-box-right-price{
		color: black;
		font-weight: 600;
		font-size: 14px;
	}
	.item-box-right-describe{
		color: #909090;
		font-size: 12px;
	}
	.item-box-right-buy{
		width: 100%;
		position: absolute;
		bottom: 0;
		display: flex;
		justify-content: space-between;
		box-sizing: border-box;
		padding-right: 12px;
	}
	.item-box-right-pick{
		background: linear-gradient(#ffa7b7,#ffcee4);
		padding: 4px 6px;
		border-radius: 12px;
		color: #ffffff;
		font-size: 12px;
	}
	.checkedStyle{
		background-color: #ffffff;
		border-left: 5px solid #ffb3c8;
		box-sizing: border-box;
		color: #ff797b;
		border-radius: 0 20px 20px 0;
	}

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小满blue

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值