问题:制作微信小程序的头部导航,点击导航就滑动到相应的标记区,随着页面的滑动,自动切换高亮显示所做导航。
方案:
- 点击导航滑动到标记点
- 计算屏幕所在导航区域
- 注意事项
1. 点击导航滑动到标记点
页面最顶端节点(放在页面最前面),用于计算页面离屏幕的高度
<view id='top'></view>
导航节点
<view class="tab" style="opacity: {
{
-scrollTop/200}}" id='tab'>
<view wx:for='{
{
tab}}'
wx:key='index'
class="tab-item {
{
currentTab==index?'active':''}}"
data-current="{
{
index}}"
bindtap="tabChange">
{
{
item}}
</view>
</view>
导航数据:
tab: ['商品','店铺','评价','详情']
导航样式:
.tab {
position: fixed;
top: 0;
z-index: 9;
width: calc(100% - 160rpx);
padding: 0 80rpx;
display: flex;
align-items: center;
justify-content: space-between;
background: #fff;
opacity: 0;
}
.tab-item {
height: 64rpx;
line-height: 64rpx;
font-size: 28rpx;
color: #999;
text-align: center;
border-bottom: 6rpx solid #fff;
}
.active {
color: #56ab2f;
border-bottom: 6rpx solid #a8e063;
transition: width 0.4s;
}
页面滑动监听
// 页面滑动监听/导航滑动监听
onPageScroll: function (e) {
this.getTopHeight();
this.scrollSetTab();
if (!navHeight) this.getNavHeight();
},
计算“页面”顶端到“手机屏幕”顶端的距离,rect.top 为标记点到手机屏幕顶部的距离,超出(滑过)为负数
// 头部的距离
getTopHeight() {
let query = wx.createSelectorQuery();
query.select('#top').boundingClientRect((rect) => {
this.setData({
scrollTop: rect.top
})
}).exec()
},
计算导航条的高度
let navHeight = 0;
Page({
...
})
// 获取导航条的高度
getNavHeight() {
let query = wx.createSelectorQuery();
query.select('#tab').boundingClientRect((rect) => {
navHeight = rect.height + 10;
}).exec()
},
滑动到页面某个点的高度height, 页面顶端到屏幕顶端的距离 + 标记点到屏幕顶端的距离
wx.pageScrollTo({
scrollTop: height
duration: 0
});
滑动到标记点
标记点为对应的导航的索引,通过导航索引定位到所做区域
<view id='point0'></view>
<view id='point1'></view>
<view id='point2'></view>
<view id='point3'></view>
点击导航滑动到标记点
// 导航切换
tabChange(e) {
let index = e.target.dataset.current;
this.setScrollTop(index);
this.setData({
currentTab: index
})
},
页面所在的高度height = 页面顶端top高度 + 标记点rect.top的高度
// 滑动到某处 页面顶端top高度 + 标记点rect.top的高度 = 所在的高度,navHight为导航条的高度
setScrollTop(index) {
let query = wx.createSelectorQuery();
query.select(`#point${
index}`).boundingClientRect((rect) => {
let scrollTop = this.data.scrollTop;
wx.pageScrollTo({
scrollTop: rect.top - scrollTop - navHeight,
duration: 0
});
}).exec()
},
2. 计算屏幕所在的导航区域
页面滑动所做区域检测
1.rect.top<=0 (0屏幕顶端位置) 标记点到导航的位置
2.rect.top>= - rect.height , 当rect.top +rect.height >= 0 时 为导航条在模块区域内
// 页面滑动时设置导航, index为检测模块标记点,标记点移动
scrollSetTab(index) {
let query = wx.createSelectorQuery();
let index = this.data.currentTab;
query.select(`#point${
index}`).boundingClientRect((rect) => {
if (rect.top > navHeight) {
console.log(index,'未到标记区')
this.setData({
currentTab: index -1
})
this.scrollSetTab();
}
if (-rect.top+navHeight > rect.height) {
console.log(index,'超越标记区')
this.setData({
currentTab: index+1
})
this.scrollSetTab();
}
}).exec()
3. 注意事项 ⚠️
1.标记点的ID不可为数字,可以加固定的字符串, 这里使用point+导航索引做ID,以对应导航所做的区域
<view id='point0'></view>
<view id='nav'></view>
2.所有标记点应连续,不应有部分节点隔离,不然在页面滑动到非标记区时无法判断所做区域,导致导航高亮失效
3.页面滑动检测所在区域问题,检测所在导航区域是否在当前页面,如未到当前标记区,则标记点上移,如超越标记区,这导航检测下移。如滑动到非标记区,或是两个标记区存在大面积非标记区,这里将无法检测页面,导致导航高亮失效!!!