点击上面的商品,评价,详情可以滚动到相应的地方,当从上往下滑动的时候,滑到某个地方相应的tab就会被选中
我之前的博客写过一个用scroll-view实现这个功能的demo,这篇就不用scroll-view实现。(有兴趣的可以去看看哦,第3篇)
先说这一块,锚点跳转
<view class="navs-nav" :class="{ navactivetext: index == num }" :style=" 'height:' + tophight.height + 'px;' + 'line-height:' + tophight.height + 'px;' "
@click="navbtn(index)">{
{item.name}}</view>
说明一下:style是我把小程序默认的导航栏去掉了,返回获取了那3个点和圆环到顶部的距离
navactivetext这个就是动态绑定的css,这没啥好说的
再来说点击事件
首先点击商品这个tab,我们肯定是让它直接返回顶部的,所以需要做一个判断
navbtn(index) {
this.num = index
if (index === 0) {
this.backTop()
} else {
const data = {
isScroll:false,
index:index
}
//调用父组件的事件
this.$parent.fatherMethod(data)
}
},
// 回到顶部
backTop() {
wx.pageScrollTo({
scrollTop: 0,
duration:300
})
}
因为我们这个是一个子组件,需要调用父组件的事件,因为是自己的练习项目,所以用了$parent,实际开发最好不要这样用哈
然后到父组件啦
fatherMethod(data) {
this.isScroll = data.isScroll
let hei = this.tophight.top + this.tophight.height
let clsdata = data.index === 1 ? '.evaluate' : '.product'
const query = this.createSelectorQuery();
query.select(clsdata).boundingClientRect()
query.selectViewport().scrollOffset();
query.exec((res) => {
if (res[0] && res[1]) {
uni.pageScrollTo({
scrollTop: res[0].top + res[1].scrollTop - hei,
duration: 300
})
setTimeout(()=>{
this.isScroll = true
},1000)
}
})
}
1.this.isScroll = data.isScroll 这个是为了不和onPageScroll产生冲突,我一时没想到啥解决的办法,如果你们有好的方法记得@我一下哈,多谢
2.这个hei也是因为我把小程序默认的导航栏去掉了,所以才要减去,你们可以根据实际情况来计算
3…evaluate就是我们的评价组件,给它绑定了一个class,同理.product也是我们的详情组件
剩下的就没啥说的了呀
然后再说我们的滚动监听,滑动一定位置,我们的tab加上class
在父组件中
首先利用computed计算出,评价和详情距离顶部的距离
Distance(){
this.$nextTick(()=>{
let hei = this.tophight.top + this.tophight.height
const query = this.createSelectorQuery();
query.select('.evaluate').boundingClientRect()
query.selectViewport().scrollOffset();
query.exec((res) => {
this.evaluateDistance = res[0].top - hei
})
query.select('.product').boundingClientRect()
query.selectViewport().scrollOffset();
query.exec((res) => {
this.productDistance = res[1].scrollHeight
})
})
},
然后利用onPageScroll
onPageScroll(e) {
let scrollTop = e.scrollTop
let that = this
if(that.isScroll === true){
function scrollCurrentIndex(param){
let distance = [that.productDistance,that.evaluateDistance-20,0]
let currentIndex = [2,1,0]
for (let i = 0; i < distance.length; i++) {
if (param >= distance[i]) {
return currentIndex[i];
};
};
return currentIndex[currentIndex.length - 1];
}
const level = scrollCurrentIndex(scrollTop)
this.currentIndex = level
}
}
再说一下下,由于是自己练习的项目,距离啥的并不是特别的准备,大家可以自己进行判断哈,这段就是判断距离最顶部的距离在哪个区间,就赋值给currentIndex,最通俗的方法就是这样写
if(scrollTop<=Number(this.evaluateDistance-20)){
currentIndex = 0
}else if(Number(this.evaluateDistance-20)<=scrollTop && scrollTop<=Number(this.productDistance)){
currentIndex = 1
}else{
currentIndex = 2
}
this.currentIndex = currentIndex
}
我只是不想用这么多if,else…
然后就通过props把currentIndex传到子组件了
回到子组件
用props接收之后
watch:{
currentIndex(newval){
this.num = newval
}
},
这样就ok啦
不过有一个问题,就是我上面说的那个用isScroll进行判断,避免锚点跳转的时候被onPageScroll所干扰,我这样做虽然可以实现,但是总感觉哪个地方不好,有小伙伴有更好的方法记得@我一下哈,谢谢啦
github上有详细的教程
github项目地址:https://github.com/lsh555/TmUniapp