先来看一下效果图:
仿淘宝做的一个微信小商城的商品详情界面,点击顶部的宝贝、评论和详情标签时,页面滑动到相应的内容区域,同时滚动页面内容时,自动切换相应的导航标签。当然,这也适应于其他场景。
先来看一下wxml代码,其中一些wxml代码省略,但这并不会影响效果的实现,所以省略也无妨。
<view class="topnav" hidden='{{hiddenTopNav}}'>
<block wx:for="{{topNavArray}}" wx:key='topnav'>
<text class="{{index==navActive?'active':''}}" bindtap='goToFloor' data-floor='f{{index}}' data-index='{{index}}'>{{item}}</text>
</block>
</view>
<scroll-view scroll-y='true' scroll-with-animation='true' scroll-into-view="{{floorNum}}" style='height:{{height}}rpx;' bindscroll="scrollFloor">
<!--id="f0"表示宝贝节点-->
<view id="f0" class="childnode">
<!--商品轮播图以及商品信息的wxml代码省略 -->
</view>
<!--评论 -->
<view class='commont childnode' id="f1">
<!--评论的wxml代码省略-->
</view>
<!--商品详情 id="f2"代表详情节点-->
<view id="f2" class="childnode">
<!--商品详情的wxml代码省略-->
</view>
</scroll-view>
<!--上面的class="childecode"在样式表中并不存在,只是为了在创建查询方法时能够通过selectAll获取到所有的childnode子元素-->
首先解析一下scroll-view视图容器的一些属性,scroll-y="true"表示允许纵向滚动,scroll-with-animation="true"表示在设置滚动条位置时使用动画过渡,scroll-into-view的值为子元素的id值(即对应的id="f0"等,内部的view即为scroll-view的子元素),在小程序文档中有说明,其值为string类型,且不允许以数字开头(在循环标签数据topNavArray时,data-floor="f{{index}}"中前面要加f,避免了数字开头),设置哪个方向可滚动(scroll-y="true"即纵向滚动),则在哪个方向滚动到该元素,也就是说,如果我们动态改变scroll-into-view中的{{floorNum}}值为f0或f1或f2,那么它是不是就自动滚动到id值为f0、f1、f2的view区域了。
顶部标签导航的wxss代码
.topnav{
position:fixed;
top:0;
left:0;
height:80rpx;
background:#FE5723;
text-align: center;
z-index:9;
width:100%;
}
.topnav text{
color:#FFF;
font-size:26rpx;
display: inline-block;
margin:0 20rpx;
border-bottom:4rpx #FE5723 solid;
padding:20rpx 0 10rpx;
}
.topnav text.active{
color:#FFFF4D;
border-bottom:4rpx #FFFF4D solid;
}
在js代码中绑定的数据为
data:{
topNavArray:['宝贝','评论','详情'],
hiddenTopNav:true,//是否隐藏顶部宝贝、评论、详情标签导航
navActive:0,//活动的标签
}
在js中的onload生命周期中通过wx.getSystemInfo来获取屏幕高度,以便得到scroll-view的高度
onLoad: function (options) {
let that = this
wx.getSystemInfo({
success: function (res) {
let width =res.windowWidth
let ratio=750/width
let height = ratio*res.windowHeight
that.setData({
height: height -100, //此处减100是减去最底部加入购物车和立即购买按钮导航的高度,单位为rpx
})
}
})
}
在js中的onShow生命周期中,通过wx.createSelectorQuery()来获取各个view的id值为f0、f1和f2节点距离scroll-view顶部的top值,存入到heightArray数组中,关于wx.createSelectQuery()的用法,可以参考微信小程序文档:SelectorQuery | 微信开放文档
虽然文档描述不多,大家也可以通过度娘查找相关用法。
onShow: function () {
let that = this,heightArray=[]
setTimeout(function(){
let query = wx.createSelectorQuery()//创建节点查询器
query.selectAll('.childnode').boundingClientRect(function (rect) {
rect.forEach(function (value) {
heightArray.push(value.top)
})
that.setData({
heightArray
})
}).exec()
},1000) //此处最好用延时,否则获取的结果有可能是null,也有可能值不准确。
}
点击标签,改变当前标签样式和滑动到相应的内容区域
标签中绑定的goToFloor事件,通过获取标签中的data-floor和data-index来改变data中的floorNum和navActive值,navActive改变可以改变标签的样式(wxss中text.active样式),floorNum改变可以改变scroll-view中scroll-into-view的属性值,以达到滚动到相应id值的view区域的目的。
goToFloor:function(e){
let that = this
var floorNum = e.currentTarget.dataset.floor;
var index = e.currentTarget.dataset.index;
that.setData({
floorNum: floorNum,
navActive: index
});
}
滚动内容区域,自动切换相应的标签
在srcoll-view中绑定滚动事件scrollFloor,利用滚动条与顶部的距离值scrollTop多少判断是否显示或隐藏标签导航,另外将scrollTop值与heightArray数组中的值分别比较得出活动的标签下标值。
scrollFloor:function(e){
let that = this,
heightArray=that.data.heightArray, //存储各节点距离scroll-view顶部的top值
hiddenTopNav,//是否隐藏标签导航
scrollTop=e.detail.scrollTop,//scroll-view滚动条距顶部的距离
navActive //活动的节点
//利用三元运算符得出hiddenTopNav的值,如果scrollTop大于100,则显示标签导航,否则隐藏
hiddenTopNav = scrollTop > 50 ? false : true
//将scroll-view滚动条距顶部的距离与各节点距离scroll-view顶部的top值比较,得出活动的标签下标
if(scrollTop>=heightArray[0]&&scrollTop<heightArray[1]){
navActive=0
} else if (scrollTop >= heightArray[1] && scrollTop < heightArray[2]){
navActive=1
}else{
navActive=2
}
that.setData({
hiddenTopNav,
navActive
})
}
真机模拟演示时滚动内容区域自动切换相应标签会延时,网上说是wx.createSelectorQuery()存在的问题,无法解决。如果有大神有更好的方法解决延时问题,请告知,谢谢!