左侧导航与右侧内容联动
一、首先是点击左侧导航,我们右侧内容需要滑动至相应的位置。
思路是:点击左侧某一项,获取该元素的id,也就是左侧view的id,然后动态传到右侧内容的scroll-into-view,scroll-into-view的值为某个子元素的id,
这里的子元素说的是右侧的view,我们将左侧view的id和右侧view的id设置为同一个值时,这样当左侧id发生变化时,scroll-into-view会帮助我们将右侧view进行相应的变化。
如图:
数据不同,data-id='a{{item.id}}'替换成你数据的参数id(左侧栏数据的id)
二、接下来是右侧滚动,左侧对应选中,也就是高亮。
思路是:既然是滚动,我们需要用到scroll-view中的bindscroll属性(绑定滚动事件,和bindtap点击事件类似,点击触发bindtap监听,滚动触发bindscroll监听),
每次右侧滚动时,我们需要计算当前滚动的高度,当滚动超过左侧分类商品在右侧中占据的高度时,我们将动态修改左侧导航的id。
实际上当数据都显示的时候,我们计算每一项分类在右侧占据的高度,当滚动超过这个高度时,我们就修改左侧导航的id,这样我们就实现了高亮。
如图:
需要注意的是以上的红色圈部分,两个图中的红色圈id要一样
计算右侧占据高度的方法是通过wx.createSelectorQuery()。
我的数据是{{good}}这个,每个人的数据不一样,但方法是相通的,按照我的文字和图进行操作是一定可以实现的。
三、最后一点问题
我们在判断滚动的高度是否超出时,最好给最初的scrollTop加上10,因为如果为0,当我点击第二个分类时,滑动可能还没有超出第一个分类占据的高度,那么高亮就会发生计算错误;还有就时如果分类中后面的商品过少,滑动时高亮也没有发生变化,所以最好时在最后的一个分类上做一些处理,比如加上占据高度,如图。
源码部分
js:
data: {
winHeight: 0,
good: [],
contentActive: '', // 内容栏id
navActive: 0, // 导航栏选中id
heightArr: [],
containerH: 0,
},
onLoad: function () {
// 获取窗口可用高度
wx.getSystemInfo({
success: res => {
this.setData({
winHeight: res.windowHeight
});
}
});
// 在请求网络数据之后里面---------
this.setData({
good: res
})
this.setHeightArr();
});
// 在请求网络数据之后里面写以上-------
},
setHeightArr:function(){
let query = wx.createSelectorQuery().in(this);
let heightArr = [];
let s = 0;
query.selectAll('.vertical-list').boundingClientRect((react) => {
react.forEach((res) => {
s += res.height;
heightArr.push(s)
});
this.setData({
heightArr: heightArr
})
});
query.select('.content').boundingClientRect((res) => {
// 计算容器高度
this.setData({
containerH: res.height
})
}).exec();
},
onScroll(e) {
let scrollTop = e.detail.scrollTop;
scrollTop += 10;
let scrollArr = this.data.heightArr;
if (scrollTop >= scrollArr[scrollArr.length - 1] - this.data.containerH) {
return
} else {
for (let i = 0; i < scrollArr.length; i++) {
if (scrollTop >= 0 && scrollTop < scrollArr[0]) {
console.log('==============aaa' + scrollTop + "==" + scrollArr[0]);
this.setData({
navActive: 0
})
} else if (scrollTop >= scrollArr[i - 1] && scrollTop < scrollArr[i]) {
console.log('==============bbb' + scrollTop + "==" + scrollArr[i]);
this.setData({
navActive: i
})
}
}
}
},
chooseType: function(e) {
let id = e.currentTarget.dataset.id;
let index = e.currentTarget.dataset.index;
console.log('=============id' + id + "--" + index);
this.setData({
toView: id,
navActive: index
})
},
wxml:
<view class="book-box">
<view class="swiper-vertical-tab">
<scroll-view class='swipter-nav' scroll-y="true" style="height:{{winHeight}}px;">
<view wx:for="{{good}}" wx:key="item" class="{{index===navActive ? 'active' : ''}}" bindtap="chooseType" data-id='a{{item.id}}' data-index='{{index}}'>
{{item.foodType}}
</view>
</scroll-view>
</view>
<view class="content content-class">
<scroll-view class="swiper-vertical-box" scroll-y="true" style="height:{{winHeight}}px;" scroll-into-view="{{toView}}" scroll-with-animation="true" bindscroll="onScroll">
<view class="vertical-list" id="a{{item.id}}" wx:for="{{good}}" wx:key="foodType" wx:for-index="idx">
<text class="title">{{item.foodType}}</text>
<block wx:if="{{item.data.length}}">
<view class="type-detail">
<view wx:for="{{item.data}}" wx:key="foodDetail" wx:for-index="jdx">
<navigator url="/pages/good/index?id={{item.objectId}}">
<image src="{{item.menu_logo}}" mode="aspectFill"></image>
<view class="book-detail">
<text>{{item.menu_name}}</text>
<view>
<text class="money">¥{{item.price}}</text>
<view class="operations smallsize">
销量:{{item.sale_number}}
</view>
</view>
</view>
</navigator>
</view>
</view>
</block>
<block wx:else>
<view class='noshop'>暂无商品</view>
</block>
</view>
</scroll-view>
</view>
</view>
wxss:
page {
background: #f0f0f0;
font-family: "微软雅黑",
Helvetica,
Arial,
"Hiragino Sans GB",
"Source Han Sans CN",
"PingFang SC",
Roboto,
"Heiti SC",
"Microsoft Yahei",
sans-serif;
background: #fff;
width: 100%;
height: 100%;
}
.book-box .content {
flex: 1;
background: #fff;
height: 100%;
}
.swiper-tab {
margin-top: 10px;
height: 20px;
padding: 10px 0;
background: #fff;
display: flex;
font-size: 17px;
line-height: 20px;
border-bottom: 1px solid #e6e6e6;
}
.swiper-tab-list {
flex: 1;
text-align: center;
position: relative;
color: #787878;
}
.swiper-tab-list:first-of-type {
border-right: 1px solid #c8c8c8;
}
.swiper-tab-list.on {
color: #fa4b22;
}
.swiper-tab-list.on::after {
content: "";
height: 2px;
width: 100px;
background: #fa4b22;
position: absolute;
left: 50%;
margin-left: -50px;
bottom: -10px;
}
.book-box {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
bottom: 0;
display: flex;
overflow: scroll;
}
.book-box, .order-box {
width: 100%;
position: relative;
box-sizing: border-box;
}
.swiper-vertical-box {
box-sizing: border-box;
flex: 1;
}
.order-box {
background: #fff;
}
.swiper-vertical-tab {
width: 200rpx;
left: 0px;
top: 0;
height: 100%;
}
.swiper-vertical-tab view {
height: 50px;
font-size: 15px;
color: #505050;
text-align: center;
box-sizing: border-box;
padding-top: 12px;
}
.swiper-vertical-tab {
background: #eee;
}
.swiper-vertical-tab view.active {
background: #fff;
}
.swiper-vertical-box .vertical-list {
/* height: 300px; */
}
.swiper-vertical-box .vertical-list .title {
height: 40px;
padding-left: 20px;
background: #f5f5f5;
color: #646464;
line-height: 40px;
font-size: 15px;
display: block;
}
.type-detail {
background: #fff;
}
.type-detail>view {
border-bottom: 1px solid #e5e5e5;
margin-left: 10px;
overflow: hidden;
padding-left: 80px;
box-sizing: border-box;
position: relative;
height: 92px;
width: 100%;
margin-bottom: -1px;
}
.type-detail view image {
width: 70px;
height: 70px;
border-radius: 6px;
margin-top: 10px;
/* border: 1px solid #ccc; */
float: left;
margin-bottom: 10px;
position: absolute;
left: 0;
top: 0;
}
.book-detail {
padding-right: 20px;
}
.book-detail>text {
font-size: 15px;
color: #505050;
margin-top: 10px;
display: block;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
font-weight: bold;
}
.book-detail button, .book-result-detail button {
float: left;
width: 27px;
height: 28px;
border-radius: 14px;
}
.book-detail>view text {
float: left;
}
.book-detail>view view {
float: left;
}
.book-detail>view {
width: 100%;
overflow: hidden;
position: relative;
height: 28px;
display: flex;
align-items: center;
justify-content: space-between;
}
.book-detail button.reduce, .book-result-detail button.reduce {
background: url(http://bmob-cdn-8770.b0.upaiyun.com/2017/03/01/3b2b07294075d7b78025de3a115733c1.png) no-repeat;
background-size: 100% auto;
}
.book-detail button.add, .book-result-detail button.add {
background: url(http://bmob-cdn-8770.b0.upaiyun.com/2017/03/01/23438bf040336dd980b7bfdd294d0265.png) no-repeat;
background-size: 100% auto;
}
.book-detail .money {
font-size: 15px;
color: #fa4b22;
line-height: 27px;
}
.operations text {
line-height: 27px;
color: #333;
width: 35px;
display: block;
text-align: center;
}
.Bill-layer {
width: 100%;
height: 100%;
background: #000;
opacity: 0.5;
position: fixed;
left: 0;
top: 0;
z-index: 1;
}
.Bill {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
z-index: 2;
}
.takeBill {
height: 50px;
background: #fff;
position: relative;
}
.takeBill .box-right {
width: 120px;
height: 52px;
background: #fa4d22;
position: absolute;
right: 0;
top: -1px;
border-radius: 0;
color: #fff;
line-height: 52px;
text-align: center;
}
.box-left {
margin-left: 30px;
}
.box-left>view {
float: left;
}
.box-left .tips {
width: 30px;
position: relative;
background: url(http://bmob-cdn-8770.b0.upaiyun.com/2017/03/01/d2c8205d404de1228042eff53f758aed.png) no-repeat left 12px;
background-size: 100% auto;
height: 40px;
position: relative;
}
.box-left .tips view {
position: absolute;
right: -5px;
top: 7px;
width: 20px;
height: 20px;
background: #f55022;
color: #fff;
border-radius: 10px;
text-align: center;
line-height: 20px;
font-size: 12px;
}
.box-left .moeny {
color: #fa4b22;
font-size: 17px;
margin-left: 10px;
margin-top: 15px;
}
.clearCart {
height: 35px;
text-align: right;
background: #f5f5f5;
}
.clearCart button {
background: none;
float: right;
color: #646464;
line-height: 35px;
font-size: 14px;
padding-left: 16px;
background: url(http://bmob-cdn-8770.b0.upaiyun.com/2017/03/01/b89dba9340a615f8805f9fa477898dfd.png) no-repeat left center;
background-size: 13px auto;
}
.clearCart button::after {
border: 0 none;
}
.book-result-detail {
overflow: hidden;
}
.book-result-detail>view {
background: #fff;
overflow: hidden;
height: 50px;
padding-top: 10px;
padding-left: 15px;
box-sizing: border-box;
padding-right: 10px;
border-bottom: 1px solid #e6e6e6;
}
.book-result-detail>view text {
float: left;
}
.book-result-detail>view view {
float: right;
}
.food-detail {
overflow: hidden;
height: 36px;
line-height: 36px;
}
.food-detail>text {
float: left;
color: #3c3c3c;
font-size: 18px;
display: block;
}
.food-detail>view {
float: right;
}
.food-detail>view text {
font-size: 15px;
color: #999;
}
.place {
height: 5px;
width: 100%;
background: #f0f0f0;
}
.order-list {
border-top: 1px solid #e6e6e6;
border-bottom: 1px solid #e6e6e6;
margin-top: -1px;
padding: 20px 15px;
}
.order-list>text {
color: #3c3c3c;
font-size: 17px;
margin-bottom: 6px;
display: block;
}
.order-list .time {
color: #999;
font-size: 13px;
text-align: right;
}
.bdt {
border-top: 1px solid #e6e6e6;
}
.hidden {
display: none;
}
.show {
display: block;
}
.noshop {
text-align: center;
margin: 40rpx;
font-size: 28rpx;
color: #999;
}
由于我是请求服务器数据,所以js中请求网络源码不能公开,本地源码可参考:https://github.com/LandQ123/littleProgressChooseGoods