业务背景:小程序原生中实现类似h5的锚点效果,而且顶部tab可以随着滑动自适应居中
话不多说,上码,粘过去直接用
※※※由于是从项目中摘出来的,所以有些没用上的代码,就没删除
wxml:
<view class="" hover-class="none" hover-stop-propagation="false">
<view class="navlist cs-fix" id="navlist">
<scroll-view scroll-x scroll-into-view="{{active_tab}}" scroll-with-animation="true">
<block wx:for="{{navList}}" wx:key="index" wx:for-item="navitem" wx:for-index="idx">
<view class="alleverynav _inline " data-idx='{{idx}}' data-name="nav{{navitem.nav_id}}" data-id="{{navitem.nav_id}}" bindtap="navBtn" id="tab_{{idx}}">
<view class="everynav {{currentCategory==idx?'active':''}}">{{navitem.nav_name}}</view>
<view wx:if="{{currentCategory==idx}}" class="botline"></view>
</view>
</block>
</scroll-view>
</view>
<scroll-view scroll-into-view="{{scrollInTo}}" scroll-y="true" bindscroll="scrolling" style="height: 100vh;" class="{{showNull ? 'scrollbox' : ''}}">
<block wx:for="{{navList}}" wx:key='index' wx:for-item='itemName'>
<view id="nav{{itemName.nav_id}}" class="every eve{{index+1}}">这是{{itemName.nav_name}}</view>
</block>
<view class="" style="width: 100%;height: 80rpx;"></view>
</scroll-view>
</view>
js:
Page({
data: {
currentCategory: 0,
moveStartPos: 0,
active_tab: 'tab_0',
navList: [{
nav_name: '不知道咋说',
nav_id: 0
},
{
nav_name: '准备好了吗',
nav_id: 1
},
{
nav_name: '来吧',
nav_id: 2
},
{
nav_name: '开始',
nav_id: 3
},
{
nav_name: '哎呀',
nav_id: 4
},
{
nav_name: '出错了',
nav_id: 5
},
{
nav_name: '算了',
nav_id: 6
},
],
},
onLoad: function (options) {},
onReady: function() {
setTimeout(()=>{
this.tabfn()
},500)
},
navBtn: function (e) {
let id = e.currentTarget.dataset.id
let idx = e.currentTarget.dataset.idx;
this.setData({
active_tab: 'tab_' + ((idx - 2) < 0 ? 0 : (idx - 1)),
currentCategory: id,
scrolly: true,
scrollTop: this.data.jltop
}, () => {
this.setData({
scrollInTo: e.currentTarget.dataset.name,
})
})
wx.createSelectorQuery().select('#navlist').boundingClientRect((rect) => {
// 节点的上边界坐标
let top = rect.top;
if (top == 0) {
this.setData({
showNull: true
})
} else {
this.setData({
showNull: false
})
}
}).exec()
},
scrolling(e) {
wx.createSelectorQuery().select('#navlist').boundingClientRect((rect) => {
let top = rect.top;
if (top == 0) {
this.setData({
scrolly: true
})
} else {
this.setData({
scrolly: false
})
}
}).exec()
// 将当前的距离传入
this.onScrollViewScroll({
scrollTop: e.detail.scrollTop
})
},
onScrollViewScroll(e) {
// 当前滚动的距离
let scrollTop = e.scrollTop
// moveStartPos记录着上一次滚动完成时的位置, 用于判断滚动方向
// 如果现在的滚动距离大于moveStartPos说明正在往下滚动
if (scrollTop > this.data.moveStartPos) {
this.setData({
moveStartPos: scrollTop
})
// 遍历每个商品距离顶部的距离
this.data.navList.forEach((item, index) => {
// 如果滚动的距离大于某个商品到顶部的距离说明该商品到了顶部, 减10是为了减少触发距离
if (Number(scrollTop) > item.top - 58) {
// 当前分类的索引小于满足条件的商品索引就赋值, 跳到下一个分类
if (this.data.currentCategory < index) {
this.setData({
currentCategory: index,
active_tab: 'tab_' + ((index - 2) < 0 ? 0 : (index - 2)),
})
}
}
})
// 如果现在的滚动距离小于moveStartPos说明正在往上滚动
} else if (scrollTop < this.data.moveStartPos) {
this.setData({
moveStartPos: scrollTop
})
this.data.navList.forEach((item, index) => {
if (Number(scrollTop) < item.top - 58) {
if (this.data.currentCategory >= index) {
this.setData({
currentCategory: index ? index - 1 : index,
active_tab: 'tab_' + ((index - 2) < 0 ? 0 : (index - 2)),
})
}
}
})
}
},
tabfn: function () {
this.animation = wx.createAnimation()
var that = this
var arr = []
// 页面准备完成之后获取每个分类距离顶部的高度, 存储在数组productsTop中
setTimeout(function () {
var query = wx.createSelectorQuery()
var toptapArr = that.data.navList;
toptapArr.forEach((item, index) => {
query.select('#nav' + item.nav_id).boundingClientRect((res) => {
if (res) {
item.top = res.top;
that.setData({
navList: toptapArr,
distanceTop: that.data.navList[0].top
})
}
})
})
query.selectAll('.cs-fix').boundingClientRect((rect) => {
that.categoryTop = rect[0].top
}).exec()
}, 800)
},
})
wxss:
._inline {
display: inline-block;
}
.navlist .active {
font-size: 32rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
height: 75rpx;
}
.navlist .botline {
width: 48rpx;
height: 4rpx;
background: #D71C18;
border-radius: 2rpx;
margin: 0 auto;
}
.navlist .alleverynav {
margin-right: 56rpx;
}
.navlist .everynav {
font-size: 26rpx;
font-family: PingFangSC-Regular, PingFang SC;
color: #666666;
}
.navlist {
white-space: nowrap;
overflow-x: scroll;
height: 90rpx;
line-height: 90rpx;
overflow-y: hidden;
margin-bottom: 20rpx;
position: sticky;
top: 0;
background: #fff;
z-index: 100;
}
.every {
background: skyblue;
border-bottom: 1px solid rebeccapurple;
height: 1500rpx;
}
说明:只是初步实现了效果,可能不是很完善,欢迎大佬讨论交流
觉得不错,赏个关注呗😀,不胜感激Thanks♪(・ω・)ノ