商品详情页的级联滚动

实现效果:

  • 点击tab中的选项,页面上下滚动到指定位置
  • 页面滚动的指定位置,tab也选中指定的选项在这里插入图片描述

解决思路:

  1. 先给指定的位置,各添加一个唯一id,(方便后续使用 uni.createSelectorQuery().select(’#’+that.idname).boundingClientRect(function(res) 定位到我要的id位置),并在data添加一个idname变量
    比如说我的样式代码
//这里是我的tabs切换选项卡 current双向绑定当前所在下标 ,  tabChange添加切换事件
<u-tabs :list="tabs" :is-scroll="false" active-color="#E9809D" :current="current" @change="tabChange"></u-tabs>


<view style="background-color: #FFFFFF;" >
	//   这里是我的第一个id名 goods
	<u-swiper :list="swiperList" height="750" id="goods" indicator-pos="bottomRight" mode="number"></u-swiper>
	<view class=" p-2 bg-light">
		<view class="py-2">
		//  这里是我的第二个id名diary
			<view id="diary" >
				<pro-menu menuName="日记" :showRight="true" menuDetail="全部"></pro-menu>
			</view>
		//  这里是我的第三个id名hospital
			<view id="hospital" >
				<pro-menu menuName="适用机构"></pro-menu>
			</view>
			<view>
				<pro-menu menuName="推荐医师" :showRight="true" menuDetail="共两位"></pro-menu>
			</view>
			<!-- <pro-menu menuName="方案百科"></pro-menu> -->
		//  这里是我的第四个id名detail
			<view id="detail">
				<pro-menu menuName="项目明细"></pro-menu>
			</view>
		</view>
	</view>
</view>

在data中定义了几个参数

data() {
	return {
	//先默认指定第一个
		idname:'goods',
		current:0,
		isScroll :false//这个列表是存放我的id名和,该id名所处的高度的
		posList:[
			{name:'goods', height:0},
			{name:'diary', height:0},
			{name:'hospital', height:0},
			{name:'detail', height:0}
		]
	}
}
  1. 再在tabs中添加一个change事件,如果点击第一个,当前current位置 === 0,那么把idname变量赋值为你想切换到的第一个id名,在遍历posList中的id高度,实现滚动到指定位置的效果,这个时候再把 isScroll 的值 改为false 这样就可以实现,点击tabs,滚动到所属位置
// 切换tabs
tabChange(e) {
	// 这个boolean值是用来控制先点击,在上下滚动。原因是,滚动有时间过度,会产生回荡效果,
	//当isScroll 是false时,就可以滚动,当正在点击时将isScroll 设为true,这样会直接return
	//不实现滚动效果,直到isScroll 变为false
	this.isScroll = true
	// 锚点跳转
	if(e === 0) {
		this.idname= 'goods'
	}else if(e === 1) {
		this.idname = 'diary'
	}else if(e === 2) {
		this.idname = 'hospital'
	}else if(e === 3) {
		this.idname = 'detail'
	}
	const that = this
	this.current = e
	//下面这些是我自己项目中的,可能有很多不是本文章的内容,我后面会提主要内容
	
	uni.createSelectorQuery().select('#'+that.idname ).boundingClientRect(function(res){//定位到你要的class的位置
	//这个posList列表我会在**第四步**中细讲讲到,他是存放id所处高度的一个数组。
		that.posList.forEach(val => {
			//下面这些根据项目需求来,参考价值不大,就是实现页面滚动的,遍历到那个id名,
			//判断他是不是当前的点击的id名,如果是就把高度赋值给scrollTop并实现滚动效果
			//如果不是,就继续遍历
			if(val.name === that.idname && val.name === 'goods') {
				uni.pageScrollTo({
					scrollTop:0,
					duration: 100
				});
			}else if(val.name === that.idname ){
				uni.pageScrollTo({
					
					// #ifdef H5
						scrollTop:(parseInt(val.height - 100 )),
					// #endif
					// #ifdef APP-PLUS
						scrollTop:(parseInt(val.height - 120 )),
					// #endif
					duration: 100
				});
			} 
		})
		//该方法的前几行有提到isScroll ,这个时候我们的点击滚动已经完成,可以把isScroll 改为false了,
		setTimeout(() => {
			that.isScroll = false
		},250)
	}).exec()
	
},
  1. 监听页面滚动,实现滚动效果,我在这里使用的是uniapp的页面生命周期onPageScroll来监听。方法参数中的e.scrollTop,是距离顶部的高度,这个有很多坑,后续在慢慢说,关于下面代码有很多问题,参考性不大,主要看我讲解和注释,各位大神嘴下留情。
    这个生命周期主要作用是监听页面滚动到什么位置,tabs中的current也跳转指定位置
onPageScroll:function(e) {
	//这一部分就是我第二步中所说的,控制滚动,实现先点击后滚动,如果还在点击,isScroll的值为true,直接return
	if(this.isScroll) {
		// console.log('联动');
		return
	}
	//我再用真机调试的时候和h5端出现了差异性,所以分了两个方案app和H5。关于后面减去的100是我项目中的问题 ,这里不多赘述
	//这个地方的主要作用是,遍历posList中的数据,判断当前页面所处位置范围,更改tabs中的current,
	//下面我是用(index - 1)中的高度 - index中的高度,
	// #ifdef APP-PLUS
		for( var i = 0;i< (this.posList.length -1); i++) {
			if(this.posList[0].height <= e.scrollTop && e.scrollTop < (this.posList[1].height - 120) ) {
				this.tabCurrent = 0
			}else if((this.posList[1].height - 120) <= e.scrollTop && e.scrollTop < (this.posList[2].height - 120)) {
				this.tabCurrent = 1
			}else if((this.posList[2].height - 120) <= e.scrollTop && e.scrollTop < (this.posList[3].height - 120)) {
				this.tabCurrent = 2
			}else if((this.posList[0].height - 120) <= e.scrollTop ) {
				this.tabCurrent = 3
			}
		}
	// #endif
	// #ifdef H5
		for( var i = 0;i< (this.posList.length -1); i++) {
			if(this.posList[0].height <= e.scrollTop && e.scrollTop < (this.posList[1].height - 100) ) {
				this.tabCurrent = 0
			}else if((this.posList[1].height - 100) <= e.scrollTop && e.scrollTop < (this.posList[2].height - 100)) {
				this.tabCurrent = 1
			}else if((this.posList[2].height - 100) <= e.scrollTop && e.scrollTop < (this.posList[3].height - 100)) {
				this.tabCurrent = 2
			}else if((this.posList[0].height - 100) <= e.scrollTop ) {
				this.tabCurrent = 3
			}
		}
	// #endif
	
},
  1. 下面第四步我们开始讲上面一直提到的posList到底是怎么知道各个id所处高度的,首先,我们需要在onready生命周期中来完成这一步骤,有人可能会想,为啥一定是onready呢,不能是onload,oninit,onshow嘛。这个我给你放个官方文档的链接你自己品读。
    我这里用onready的原因是,onready监听页面初次渲染完成。说明这个时候我们所设置的几个id也已经渲染完成,这样就可以用uni.createSelectorQuery().select(’#’+val.name).boundingClientRect(function(res) 方法获取id所处高度了。
    那为啥onload,onshow,oninit不行呢,那就是他们还没渲染完吧,具体我也没动手试验过,但是用onready准没错。
    下面放代码:
onReady() {
	//	这里用setTimeout来控制延时,是为了获取全部的id高度,id越多,耗时就越多,这也是一个弊端,
	setTimeout(() => {
		this.posList.forEach(val => {
			//遍历各个id名,获取高度并添加到数组中,这就有二三步骤中我们使用的id高度数组了
			uni.createSelectorQuery().select('#'+val.name).boundingClientRect(function(res){//定位到你要的class的位置
				val.height = res.top
			}).exec()
		})
	},500)
},

总结

  • 我使用到的这个方法有点笨和冗长,但是也是一个方法,如果小伙伴们有更好的方法希望能跟我分享分享。
  • 文章中第三部分中提到的onPageScroll是页面生命周期,如果小伙伴使用的scroll-view包裹的,就不能适用了,至于怎么用,那就要好好翻读文档,百度问题了。
  • 我不知道你们有没有看懂那个参数:isScroll,其实这个作用很大,我上边讲过了,但是我还想再捋一遍

我实现这个效果,有两个主要的步骤,
①。点击tabs的按钮,实现滚动
②.滚动页面,tabs中的选项会联动
第二步中实现的是①,第三步中实现的是②。
在①中细分两个操作,一个是点击,一个是滚动,注意这个时候需要滚动,那么这就和②中的生命周期监听滚动有关联,其关联是,滚动有时间过过渡,就在点击tabs的这几百毫秒的时间内,此时新的id名已经赋值给了idname,就差滚动到指定位置了,这一滚动生命周期onPageScroll就监听到了,发现当前页面的高度还是在老的id名(上一个id名)所处范围内,那页面不能滚动,当时页面刚滚动几px就被onPageScroll生命周期监听到,就给拉回来了。于是就出现了,回荡的效果。也没法滚动到指定位置。
那我们就这个一个专门的变量控制一下,在点击滚动的时候,就不让生命周期监听(即不操作生命周期里的方法)。等待点击tabs滚动完成之后,在继续监听。

又解决了一个问题,真开心
结束,----散会 o( ̄▽ ̄)ブ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值