微信小程序开发:实现列表滚动上下联动效果的方法详解
创作时间:
作者:
@小白创作中心
微信小程序开发:实现列表滚动上下联动效果的方法详解
引用
1
来源
1.
https://www.finclip.com/news/f/85230.html
在微信小程序开发中,实现列表滚动上下联动效果是一个常见的需求。本文将详细介绍如何通过微信小程序原生的scroll-view组件实现这一功能,包括原理介绍、页面布局、样式设计和逻辑处理等关键步骤。
1. 背景
最近在开发公司的一款小程序时,遇到了一个需求:在列表滚动时,顶部的tab栏需要跟随一起联动;同时,点击tab栏时,列表数据也需要相应地联动。下面是实现的效果图:
- 顶部的头部区域不跟随列表滚动
- 头部区域以下属于滚动区域
2. 实现
2.1 原理介绍
实现这一功能主要借助微信小程序原生的scroll-view组件。具体来说:
- 使用
scroll-into-view
属性,可以实现点击顶部的tab栏,将页面滚动到指定的列表位置 - 使用
bindscroll
事件,可以获取当前页面滚动的距离,根据滚动的距离来切换tab栏
2.2 页面布局代码
界面整体布局分为两部分:头部固定区域和可滚动列表区域。其中,可滚动列表区域的标题栏在滚动到一定距离后需要固定在顶部。
<!--index.wxml-->
<view class="list">
<!--顶部固定区域-->
<view style="height: 88rpx;width: 100%;background-color: burlywood;text-align: center;">头部区域</view>
<!--可滚动区域-->
<scroll-view scroll-y="true"
style="width: 100%; height: {{scrollAreaHeight}}px;"
bindscroll="scroll"
scroll-into-view="{{scrollToItem}}"
scroll-with-animation="true"
scroll-top="{{scrollTop}}">
<!--水平滚动的tab栏-->
<scroll-view scroll-x="true"
style="height: 88rpx;width: 100%;">
<view class="head-area {{float ? 'head-float' : ''}}">
<view class="head-area-item {{curSelectTab === index ? 'head-area-item-select' : ''}}"
wx:for="{{appGroupList}}"
bindtap="tabClick"
data-index="{{index}}">
{{item.name}}
</view>
</view>
</scroll-view>
<!--数据列表-->
<view class="list-group"
style="height: {{listGroupHeight}}px;">
<view class="list-group-item"
id="v_{{index}}"
wx:for="{{appGroupList}}"
data-index="{{index}}">
<view class="group-name">
{{item.name}}
</view>
<view class="group-children">
<view wx:for="{{item.children}}"
class="group-children-item"
style="width: {{itemWidth}}px;">
<image src="{{item.url}}"></image>
<view>{{item.name}}</view>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
在布局代码中有几个关键点需要注意:
scrollAreaHeight
:滚动区域的高度计算。通过获取当前设备的窗口高度减去顶部固定区域的高度- 水平tab栏是否置顶:根据页面的滚动距离来判断,如果滚动距离大于或等于水平tab栏的高度,则置顶
- 数据列表的id设置:
id="v_{{index}}"
,后续点击tab栏滚动到指定位置就是根据这个id实现的
2.3 样式代码
/*index.wxss*/
.list {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.head-area {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
height: 88rpx;
width: 100%;
padding: 0 10;
}
.head-area-item {
display: flex;
height: 88rpx;
text-align: center;
width: 150rpx;
align-items: center;
justify-content: center;
}
.head-area-item-select {
color:#09bb07;
}
image {
width: 88rpx;
height: 88rpx;
}
.list-group {
display: flex;
width: 100%;
height: 1000%;
flex-direction: column;
}
.list-group-item {
display: flex;
width: 100%;
background-color:#aaa;
flex-direction: column;
}
.group-name {
height: 88rpx;
display: flex;
text-align: center;
align-items: center;
margin-left: 20rpx;
}
.group-children {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
}
.group-children-item {
height: 160rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.head-float {
position: fixed;
top: 88rpx;
background-color:#ffffff;
}
2.4 逻辑代码
// index.js
Page({
heightArr: [], // 记录scroll-view滚动过程中距离顶部的高度
distance: 0,
data: {
appGroupList:[
{name:"分组01",children:[{"name":"测试0","url":"/images/bluetooth.png"},
{"name":"测试1","url":"/images/bluetooth.png"},
{"name":"测试2","url":"/images/bluetooth.png"},
{"name":"测试3","url":"/images/bluetooth.png"},
{"name":"测试4","url":"/images/bluetooth.png"},
{"name":"测试5","url":"/images/bluetooth.png"},
{"name":"测试6","url":"/images/bluetooth.png"},
{"name":"测试7","url":"/images/bluetooth.png"}]},
{name:"分组02",children:[{"name":"测试0","url":"/images/bluetooth.png"},
{"name":"测试1","url":"/images/bluetooth.png"},
{"name":"测试2","url":"/images/bluetooth.png"},
{"name":"测试3","url":"/images/bluetooth.png"},
{"name":"测试4","url":"/images/bluetooth.png"},
{"name":"测试5","url":"/images/bluetooth.png"},
{"name":"测试6","url":"/images/bluetooth.png"},
{"name":"测试7","url":"/images/bluetooth.png"}]},
{name:"分组03",children:[{"name":"测试0","url":"/images/bluetooth.png"},
{"name":"测试1","url":"/images/bluetooth.png"},
{"name":"测试2","url":"/images/bluetooth.png"},
{"name":"测试3","url":"/images/bluetooth.png"},
{"name":"测试4","url":"/images/bluetooth.png"},
{"name":"测试5","url":"/images/bluetooth.png"},
{"name":"测试6","url":"/images/bluetooth.png"},
{"name":"测试7","url":"/images/bluetooth.png"}]},
{name:"分组04",children:[{"name":"测试0","url":"/images/bluetooth.png"},
{"name":"测试1","url":"/images/bluetooth.png"},
{"name":"测试2","url":"/images/bluetooth.png"},
{"name":"测试3","url":"/images/bluetooth.png"},
{"name":"测试4","url":"/images/bluetooth.png"},
{"name":"测试5","url":"/images/bluetooth.png"},
{"name":"测试6","url":"/images/bluetooth.png"},
{"name":"测试7","url":"/images/bluetooth.png"}]},
{name:"分组05",children:[{"name":"测试0","url":"/images/bluetooth.png"},
{"name":"测试1","url":"/images/bluetooth.png"},
{"name":"测试2","url":"/images/bluetooth.png"},
{"name":"测试3","url":"/images/bluetooth.png"},
{"name":"测试4","url":"/images/bluetooth.png"},
{"name":"测试5","url":"/images/bluetooth.png"},
{"name":"测试6","url":"/images/bluetooth.png"},
{"name":"测试7","url":"/images/bluetooth.png"}]},
],
itemWidth: wx.getSystemInfoSync().windowWidth / 4,
scrollAreaHeight:wx.getSystemInfoSync().windowHeight - 44,
float:false,
curSelectTab:0,
scrollToItem:null,
scrollTop: 0,//到顶部的距离
listGroupHeight:0,
},
onReady:function() {
this.cacluItemHeight();
},
scroll:function(e){
console.log("scroll:",e);
if(e.detail.scrollTop>=44){
this.setData({
float :true
})
}else if(e.detail.scrollTop<44) {
this.setData({
float :false
})
}
let scrollTop = e.detail.scrollTop;
let current =this.data.curSelectTab;
if(scrollTop >=this.distance) {
//页面向上滑动
//列表当前可视区域最底部到顶部的距离 超过 当前列表选中项距顶部的高度(且没有下标越界),则更新tab栏
if(current + 1 <this.heightArr.length && scrollTop >=this.heightArr[current]) {
this.setData({
curSelectTab: current + 1
})
}
}else{
//页面向下滑动
//如果列表当前可视区域最顶部到顶部的距离 小于 当前列表选中的项距顶部的高度,则切换tab栏的选中项
if(current - 1 >= 0 && scrollTop <this.heightArr[current - 1]) {
this.setData({
curSelectTab: current - 1
})
}
}
//更新到顶部的距离
this.distance = scrollTop;
},
tabClick(e){
this.setData({
curSelectTab: e.currentTarget.dataset.index,
scrollToItem:"v_"+e.currentTarget.dataset.index
})
},
//计算每一个item高度
cacluItemHeight() {
let that =this;
this.heightArr = [];
let h = 0;
const query = wx.createSelectorQuery();
query.selectAll('.list-group-item').boundingClientRect()
query.exec(function(res) {
res[0].forEach((item) => {
h += item.height;
that.heightArr.push(h);
})
console.log(that.heightArr);
that.setData({
listGroupHeight: that.heightArr[that.heightArr.length - 1 ]
})
})
},
})
在逻辑代码中最主要的有两个地方:
cacluItemHeight
:计算列表中item的高度数组,并将最终计算的结果保存在heightArr
数组中。heightArr
数组中的每一项的值是在前一项的基础之上进行累加。scroll
:判断当前的滚动方向,根据滚动判断当前的方向,然后根据滚动的距离设置当前选择的tab。
基于以上内容,可以实现想要的滚动联动、切换tab联动效果。
热门推荐
神经网络问题之一:梯度消失(Vanishing Gradient)
角膜塑形镜的护理液可以泡隐形眼镜吗
减脂需要热量,减脂需要热量缺口吗?
六味地黄丸的副作用和危害有哪些?六味地黄丸的使用注意事项!
开源协议在中国的法律地位是什么
智慧赋能、业态升级,上海徐汇打造示范性智慧菜市场
如何使用 Git 进行多人协作开发(全流程图解)
如何自己练英语口语
如何提升直播的内容质量和观众体验
女性失眠:12种助眠食材泡水推荐,改善睡眠质量全攻略
100艘甲醇船队建造计划,开始启动!
异维A酸红霉素凝胶可以去黑头吗
如何查看交换机的CPU使用率
民事责任构成要件有哪些
劳务派遣员工如何在国企中实现转正:政策解读与实践经验分享
网络主播“转正”更待转型
基于LSTM神经网络组合模型的农产品期货价格预测
每年超百万动物死于塑料污染:一场迫在眉睫的生态危机
100多种四季蔬菜种植时间表
泡澡的功效与作用
单方车祸是不是可以不报警处理
炒瘦肉的秘密武器:5个技巧,让肉质更嫩滑!
丁醇气体的危害及接触极限值
劳务外包员工如何满足转正条件并成功转为正式员工?
智齿一般长几年停止生长?智慧拔除的时机与必要性
【科普营养】抗氧化、抗衰老、提高免疫力、减少内脏脂肪 ...PQQ到底是什么?
糖尿病患者能否食用面粉?医生的专业建议来了
如何保护交通事故现场证据不被破坏?
头皮老长毛囊炎,你可以这样应对
上海普陀升级教育"政策包" 集团跨学段共享优质教育