实现效果:
- 点击tab中的选项,页面上下滚动到指定位置
- 页面滚动的指定位置,tab也选中指定的选项
解决思路:
- 先给指定的位置,各添加一个唯一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}
]
}
}
- 再在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()
},
- 监听页面滚动,实现滚动效果,我在这里使用的是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
},
- 下面第四步我们开始讲上面一直提到的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( ̄▽ ̄)ブ