微信小程序开发:实现列表滚动上下联动效果的方法详解
创作时间:
作者:
@小白创作中心
微信小程序开发:实现列表滚动上下联动效果的方法详解
引用
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联动效果。
热门推荐
英语退出高考?摆摊被罚16万?原来劲爆“新闻”由AI炮制
“取经之路”=“仕途”,借孙悟空的形象变化,解读明代士人精神
索达吉日修闭关要诀
幽门螺旋杆菌感染的四大特征表现及预防建议
“投5000元月入3万”,家庭咖啡馆真的能赚钱吗?
鼠标手被列入职业病:如何预防与缓解?
武汉租房攻略:从找房到入住全方位指南
如何建设特色社团团队
梦见批卷子是什么意思
脉动每天一瓶可以吗?如何科学饮用脉动?
人工智能是如何解决问题
在山东,饺子叫法有4种,最后一种、外地人直接懵圈
拒绝“牛马”工作、不再做“工具人”:新时代日本年轻人的职场觉醒与反抗
知道IP地址怎样求子网掩码
专家共识:主动脉瓣狭窄程度的分级标准及流程
中国疾控中心发布汛期健康提示:谨防血吸虫病感染
5大底妝順序教學!詳細拆解步驟讓不同膚質簡單完成無暇底妝
阴影下的生活:民众如何应对战争挑战
5本心理学经典著作,帮你更好地理解自己和他人
酒浪摇春不受寒,烛花垂烬忽堆盘,宋代夜生活为何能繁荣发展?
莆田人乡宴上的王炸,凭什么是一碗面?
咽喉一直感觉被哽住了怎么办
每天吃三个鸡蛋,身体会发生什么变化?
12岁孩子的心理特点和教育方法有哪些?大神来分析!
一文读懂,心包炎的诊断和治疗|JAMA综述
等保测评流程(非常详细)零基础入门到精通,收藏这一篇就够了
探讨生死与爱的边界,从韩剧《照明商店》的恐怖与温情出发
整形美容皮肤科医生解析:痘印的类型以及如何改善?
“Angel”的多重含义:从宗教象征到生活中的温暖与关怀
起底《黑神话:悟空》背后公司:腾讯持股5%,创始人曾是《斗战神》核心成员