微信小程序开发:实现列表滚动上下联动效果的方法详解
创作时间:
作者:
@小白创作中心
微信小程序开发:实现列表滚动上下联动效果的方法详解
引用
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联动效果。
热门推荐
国外易拉宝设计:简约而不简单的设计理念
项目需求设计:从目标设定到持续改进的完整指南
五年以上帕金森病患者的重要注意事项
商务宴请座位安排全攻略:细节决定成败
多系统集成分析:WMS系统与PLM、ERP、MES等系统的关联
鲸鱼是肉身,潜艇是钢铁,为什么鲸鱼的下潜深度比潜艇还深?
子女身高预测
风尘四侠都有选秀模板,功成名就的他们 是否超越了自身模板?
放射性食管炎的治疗方案
队报回忆温格和亨利师徒情:情如父子,互相成就
ITU-T G.65X单模光纤详解:类型、特点与应用场景
高效职场必备:掌握向上管理的5大诀窍与4个禁忌,让你成为不可或缺的职场佼佼者
30个藏在中药里的绝美名字 极具美感
干细胞治疗脑出血后遗症,不同类型干细胞的疗效分析
什么是伴侣治疗?_ 详细指南
大脑营养师:BDNF如何助你保持思维敏捷
河北工大、燕山大学,谁才是“河北第一校”?
龙年四月出生的宝宝取名
数字编码记忆法:从三十六计到扑克牌的记忆技巧
六险一金指什么意思
苹果手机中文语言设置指南
硬盘的基本知识与选购指南
鹿角每年都会自然脱落,人类为何割鹿茸,而不是捡拾脱落的鹿角?
2025年如何成为一名AI开发者(全流程攻略+资源推荐)
书画投资的核心要素:优先关注风险控制而非追求最高回报
EHT合作组织最新发现:银河系黑洞周围存在强大磁场
首套房装修必读:7种常见板材的优缺点及选购指南
成都大熊猫繁育研究基地游玩攻略
来湖南吉首吃什么?这些美食也许就是答案!
伺服电机UVW接线方法及接错处理技巧