左侧导航与右侧内容联动
一、首先是点击左侧导航,我们右侧内容需要滑动至相应的位置。
思路是:点击左侧某一项,获取该元素的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:
200
rpx
;
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:
40
rpx
;
font-size:
28
rpx
;
color:
#999
;
}
由于我是请求服务器数据,所以js中请求网络源码不能公开,本地源码可参考:https://github.com/LandQ123/littleProgressChooseGoods