开发微信小程序时,经常会遇到一些特别的功能,单页面的锚点导航,目前好像没什么开放组件可以直接用到微信小程序中,今天分享一下~
1、定义导航条内容及高度
使用循环动态展示,这样可以更好的管理页面锚点吸顶后展示的效果,并定义toView和navIdx设置目的导航条位置
初始化的时候获取scrollview所有模块的高度,为锚点滚动使用,并且获取节点距离顶部的距离
wxml
<view class="navbar-wrap"> <view class="scrollListBox {{isFixedTop?'fixed':''}}" id="navbar"> <view wx:for="{{navList}}" wx:for-index="idx" wx:key="index" bindtap='clickScroll' data-idx="{{idx}}" data-id="{{item.id}}" class="scrollListItem {{idx == navIdx ? 'onScrollNav':''}}"> {{item.name}} </view> <!-- 用于吸顶后占位 --> </view> <view class="scrollListBox" wx:if="{{isFixedTop}}"></view> </view>js:
data: {
navbarInitTop: 0, //导航栏初始化距顶部的距离 isFixedTop: false, //是否固定顶部 toView:"", navIdx:0, navList:[ { id: "list0", name:"简介" },{ id: "list1", name:"价格" },{ id: "list2", name:"周边" },{ id: "list3", name:"附近" } ],
},
onShow: function () { var that = this; let query = wx.createSelectorQuery().in(this); let heightArr =[]; let h = 0; query.selectAll('.scrollListItem').boundingClientRect((react)=>{ react.forEach((res)=>{ h+=res.height; heightArr.push(h) }) this.setData({ anchorArray:heightArr }); }).exec(); //导航栏吸顶 if (that.data.navbarInitTop == 0) { //获取节点距离顶部的距离 wx.createSelectorQuery().select('#navbar').boundingClientRect(function(rect) { if (rect && rect.top > 0) { var navbarInitTop = parseInt(rect.top); that.setData({ navbarInitTop: navbarInitTop }); } }).exec(); }
},
wxss:
.navbar-wrap { width: 100%; line-height: 102rpx;}scroll-view { height: 600px;}.scrollListBox{ width: 100%; line-height: 102rpx; background: #f6f8fc; top: 0; left: 0; z-index: 100;}.navbar-wrap .scrollListBox.fixed { position: fixed;}.scrollListItem { font-size: 28rpx; display: inline-block; width: 20%; line-height: 70rpx; color: #1A1A1A; text-align: center;}.onScrollNav{ color: #10AEFF; border-bottom: 2px solid #10AEFF;}.swiperLine { width: 30px; height: 3px; background-color: #10AEFF; border-radius: 4px; margin-left: 32rpx;}.swiper-box{ display: block; height: 100%; width: 100%;}
2、页面内容定义,锚点点击/滑动跳转后的位置
<scroll-view scroll-y scroll-into-view="{{toView}}" bindscroll="scrollTopFun" style="height:100vh;background: #f6f8fc;" scroll-with-animation="true" > <!-- 简介 --> <view class="navListView" id="list0"></view>
<!-- 价格 --> <view class="navListView" id="list1"></view>
<!-- 周边 --> <view class="navListView" id="list2"></view>
<!-- 附近 --> <view class="navListView" id="list3"></view></scroll-view>
注:这里的每个id都要和上面定义的list里的id内容一致,使用scroll-view滑动更顺畅,感觉之前写的分页后来加了scroll-view也更顺滑,还是很好用的,之前没有get到
3、监听页面滑动,动态选中当前锚点的导航条
onPageScroll: function(e) { var that = this; var scrollTop = parseInt(e.scrollTop); //滚动条距离顶部高度 var isOk = scrollTop >= that.data.navbarInitTop ? true : false; if (that.data.isFixedTop === isOk) { return false; } that.setData({ isFixedTop: isSatisfy });},
监听页面滑动事件,判断滚动条滚动的距离和元素初始与顶部的距离,并为了不会一直setData则增加死循环判断isOk 。
4、点击锚点滑动到页面导航的位置
通过获取当前view距离顶部的位置判断当前展示的内容是第几个导航条,然后导航条内容高亮展示选中
scrollTopFun: function (e) { let scrollTop=e.detail.scrollTop; let scrollArr= this.data.anchorArray; if(scrollTop>=scrollArr[scrollArr.length-1]){ return; }else { for(let i=0;i<scrollArr.length;i++){ if(scrollTop>=0&&scrollTop<scrollArr[0]){ // navIdx控制筛选块高亮显示 this.setData({ navIdx: 0 }); }else if(scrollTop>=scrollArr[i-1]&&scrollTop<scrollArr[i]) { this.setData({ navIdx: i }); } } } }, //点击锚点导航栏 clickScroll: function (e) { this.setData({ toView: e.target.dataset.id, navIdx: e.target.dataset.idx }) },
点击锚点,就可以直接定义当前想跳转的导航内容,通过toView和navIdx直接滑动到目的内容
一共分为4个步骤,不过不是特别详细,因为我觉得看这篇文章的人都是想直接解决问题,可以试下是否可以,已经用在项目中才分享的~