1、需求1:实现左侧菜单栏与右侧功能区联动~。当点击切换左侧菜单栏时需变色同时需将其对应右侧功能区节点滑动至顶部。
2、需求2:实现滑动右侧功能区,当其所处的功能区节点刚刚触顶时,需切换左侧菜单栏与之对应。
3、效果如下:
4、代码实现
需求1:
html
<!-- 侧边栏 -->
<view class="aside-main">
<scroll-view scroll-y class="scroll-Y1" :style="'height:'+ mainH" scroll-with-animation>
<view :class="num==index?'active':''" v-for="(item,index) in asideList" :key="index" @click="asid(index)">{{item.title}}
</view>
</scroll-view>
<!-- 右侧滑动区 -->
<scroll-view scroll-y class="scroll-Y2" :style="'height:'+ mainH" :scroll-into-view="rightview" scroll-with-animation @scroll="scrollright" @scrolltoupper="scrolltop" @scrolltolower="scrollbuttom">
<!-- 功能区节点 -->
<view v-for="(item,index) in asideList" :key="index" class="min" :id="'rightIndex'+index">
<view v-for="(i,j) in item.list" :key="j" class="minmi">
<image :src="i.url" class="min-img"></image>
<text>{{item.title}}</text>
</view>
</view>
</scroll-view>
</view>
css
js
// 侧边栏切换
asid(index) {
// 变色
this.num = index
// 通过uniapp的scroll-into-view实现与右侧功能区节点的切换联动
this.rightview = 'rightIndex' + index
},
需求2:
js
5、需求实测实现啦~
炒毛豆也是刚刚接触小程序。3年后台经验。后续会将学习心得不定时记录~(仅做个人笔记使用)
完整代码:
<template>
<view>
<!-- 适配小程序 -->
<!-- #ifdef MP -->
<!-- 头部搜索栏 -->
<!-- 使用组件,可参考uniapp的esaycomezi组件 -->
<search>
<!-- 具名插槽 -->
<view slot="left">
<img src="@/static/images/扫码.png" class="icon" @click="re()" />
</view>
<div class="serch" slot="center">
<img src="@/static/images/搜索.png" class="icon1" />
<input type="search" placeholder="搜索..." placeholder-style="place" @click="searchTo()" />
</div>
<button class="btn" slot="right">搜索</button>
</search>
<!-- #endif -->
<!-- 内容区 -->
<!-- 侧边栏 -->
<view class="aside-main">
<scroll-view scroll-y class="scroll-Y1" :style="'height:'+ mainH" scroll-with-animation>
<view :class="num==index?'active':''" v-for="(item,index) in asideList" :key="index"
@click="asid(index)">{{item.title}}
</view>
</scroll-view>
<!-- 右侧滑动区 -->
<scroll-view scroll-y class="scroll-Y2" :style="'height:'+ mainH" :scroll-into-view="rightview"
scroll-with-animation @scroll="scrollright" @scrolltoupper="scrolltop" @scrolltolower="scrollbuttom">
<!-- 功能区节点 -->
<view v-for="(item,index) in asideList" :key="index" class="min" :id="'rightIndex'+index">
<view v-for="(i,j) in item.list" :key="j" class="minmi">
<image :src="i.url" class="min-img"></image>
<text>{{item.title}}</text>
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
mainH: 400,
num: 0,
leftview: '',
rightview: '',
// 所有的节点坐标
nodes: [],
asideList: [{
title: "手机",
list: [{
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}]
},
{
title: "电脑",
list: [{
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}]
},
{
title: "华为",
list: [{
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}]
},
{
title: "小米",
list: [{
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}]
},
{
title: "苹果",
list: [{
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}, {
url: "../../static/images/sex5.jpg"
}]
},
{
title: "vivo",
list: [{
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}, {
url: "../../static/images/sex2.jpg"
}]
}
]
}
},
created() {
// 调用uniapp的api获取系统信息,如浏览器可视区高度
// 实现向下滑动,只有内容区可以滑动
uni.getSystemInfo({
success: (res) => {
// 将upx转换成px
// 可视区高度减去导航栏高度
this.mainH = res.windowHeight - uni.upx2px(88) + 'px';
}
})
// 得到页面加载完成时所有的.min节点的坐标位置,主要为top值
this.coordinate()
},
methods: {
// 扫码
re() {
uni.scanCode({
success: function(res) {
console.log('条码类型:' + res.scanType);
console.log('条码内容:' + res.result);
}
});
},
// 搜索
searchTo() {
// 跳转路由,跳转到搜索页面
uni.navigateTo({
url: "../searchmain/searchmain"
})
},
// 侧边栏切换
asid(index) {
// 变色
this.num = index
// 通过uniapp的scroll-into-view实现与右侧功能区节点的切换联动
this.rightview = 'rightIndex' + index
},
// 滑动触顶事件
scrolltop() {
this.num = 0
},
// 滑动触底事件
scrollbuttom() {
this.num = this.nodes.length - 1
},
// 滑动右边内容区实现与左侧菜单栏联动效果
// 监听滑动事件
scrollright(e) {
// 每一次滑动之前都做一遍跟随,用来解决侧边栏切换不联动问题(重要!!!不加是有bug的)
this.asid()
// 拿到滑动的距离(记住初始滑动距离是0!!很重要)
console.log('滑动的距离', e.detail.scrollTop)
// 遍历存储所有节点top坐标的数组nodes(默认从下标1开始,因为初始状态的左侧菜单栏与右侧功能区就是对应的!!)
for (let i = 1; i < this.nodes.length; i++) {
// 判断滑动的距离+初始节点的top值!!(这里就是为什么在上面特意提醒要牢记滑动距离的初始值是0的原因,这里将滑动距离加上初始节点的top值是为了将二者放在一个'水平线'上,便于后面比较)是否大于等于当前功能区节点的top值并且小于等于下一个的节点的top值,如果满足条件将切换左侧菜单栏变色的标识符num的值变为当前节点的i。同时需额外判断滑动的距离+初始节点的top值是否大于最后一个功能区节点的top值,因为如果不单独判断的话,原判断逻辑针对最后一个节点是满足不了并条件的。判断头部同理,同时需搭配触顶与触底事件。
if (e.detail.scrollTop + this.nodes[0] >= this.nodes[i] && e.detail.scrollTop + this.nodes[0] <= this
.nodes[i + 1]) {
this.num = i
} else if (e.detail.scrollTop + this.nodes[0] < this.nodes[1]) {
this.num = 0
} else if (e.detail.scrollTop + this.nodes[0] > this.nodes[this.nodes.length - 1]) {
this.num = this.nodes.length - 1
}
}
},
// 获取右侧内容区每个指定节点的坐标信息(即左侧菜单栏所对应的每一个功能区的顶部坐标),该方法只在created生命周期中执行一遍即可
coordinate() {
const query = uni.createSelectorQuery().in(this);
query.selectAll(".min").boundingClientRect((data) => {
// 获取每一个功能区的全部坐标对象(数组形式)
console.log("得到布局位置信息" + JSON.stringify(data));
console.log("节点离页面顶部的距离为" + data.top);
console.log(data)
// 遍历每一个功能区的全部坐标对象(数组形式),拿到所有的top坐标
for (let i = 0; i < data.length; i++) {
console.log("每个节点的top坐标", data[i].top)
// 将每个top坐标push进一个空数组nodes中
this.nodes.push(data[i].top)
}
console.log("nodes", this.nodes)
})
.exec();
}
}
}
</script>
<style>
.active {
color: red;
}
.min {
display: flex;
flex-direction: row;
justify-content: space-around;
flex-wrap: wrap;
}
.minmi {
display: flex;
flex-direction: column;
}
.min-img {
width: 150upx;
height: 100upx;
}
.aside-main {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
box-sizing: border-box;
}
.scroll-Y1 {
flex: 1;
box-sizing: border-box;
}
.scroll-Y1 view {
text-align: center;
margin: 50upx;
}
.scroll-Y2 {
flex: 3;
box-sizing: border-box;
}
.scroll-Y2 view {
text-align: center;
/* margin:20upx; */
}
.icon {
width: 50upx;
height: 50upx;
margin-top: 10upx;
}
.icon1 {
width: 30upx;
height: 30upx;
position: absolute;
top: 15upx;
left: 10upx;
}
.btn {
width: 140upx;
height: 60upx;
line-height: 60upx;
margin: 0;
padding: 0;
font-size: 30upx;
}
.serch {
height: 60upx;
flex: 2;
margin-left: 20upx;
margin-right: 20upx;
box-sizing: border-box;
border: solid 1upx #ccc;
border-radius: 10upx;
position: relative;
}
.serch input {
height: 60upx;
margin-left: 60upx;
}
</style>