微信小程序开发:实现列表滚动上下联动效果的方法详解
创作时间:
作者:
@小白创作中心
微信小程序开发:实现列表滚动上下联动效果的方法详解
引用
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联动效果。
热门推荐
车贷提前还清后还需要做什么
十年磨一剑:北京大学国际医院临床研究助力ANCA相关性血管炎精准诊治
睡眠时出汗多是怎么回事? 怎么处理?
四相五线步进电机,工作原理与应用介绍
《白日焰火》:一部悬疑犯罪片的艺术探索
实体店标准化管理:提升运营效率与顾客体验的关键
探秘二月闰月的天数与其特殊意义
用8个问题重启人生
高考怎么安排睡眠时间?
装配扭矩的检测方法
历史上真实的张飞:文武双全的美男子?
炒房融资存在哪些风险?这些风险怎样防范?
大棚出租,墙体遭雨水侵袭受损,谁之责?|寿法案例 · 蔬菜法庭
走进铁道兵博物馆,感悟铁道的钢铁故事
什么是千分尺?千分尺的工作原理和千分尺种类、品牌
从曲阳到浑源——谈北岳恒山的变迁
药品FDA注册申报资料要求详解:从法规到实操
引起反流性食管炎的原因?医生:知道它才是治疗的关键
晶闸管过流保护原理及六大参数详解
结婚证要怎么办理?一文详解办理流程、补办手续及法定结婚年龄
数字电路中的SR触发器:原理与应用
春季养生必看:3大食疗原则+10种适宜食物,轻松提升免疫力!
AI如何重塑我们的日常生活?从智能助手到未来革命
汉末三国,曹操时代10大谋士终极排行!郭嘉、司马懿竟未进前五?
如何保障冬季居住的温暖与舒适?这种保障如何体现能源的合理利用?
Cesium中实现根据最高地形瓦片生成高度图
高涵:一步一步,脚踏实地
怎样按摩能够补气血呢
工资表扣款明细:详解工资单上各种扣除项
这些年,鸳鸯、天鹅等动物界模范夫妻的恩爱真相