微信小程序开发:实现列表滚动上下联动效果的方法详解
创作时间:
作者:
@小白创作中心
微信小程序开发:实现列表滚动上下联动效果的方法详解
引用
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联动效果。
热门推荐
秋冬打卡民勤苏武沙漠景区,出片率100%!
武威雷台汉墓:铜奔马的传奇发现与艺术价值
探访“石窟鼻祖”:武威天梯山石窟的历史与艺术价值
双十一自制个性手工笔记本,你心动了吗?
手把手教你DIY高颜值手工笔记本!
乌鲁木齐严查酒驾:别拿生命当儿戏!
乌镇到西塘自驾游攻略:一路美景等你来打卡!
冬季滋补海龟汤在家轻松做
海龟汤面:传统美食的现代困境与创新
海龟保护热潮下,海龟汤还能传承吗?
在家也能做出美味海龟汤!
十一打卡延边:中国朝鲜族民俗园
秋日自驾游:长春到延边的绝美路线
香港人北上深圳山姆超市抢购热潮:跨境消费新趋势
山姆会员店成港人新宠!
微信安全中心:保护你的转账记录
上高原下深海,它们何以入选全国十大考古新发现?
青铜器和铁器哪个更早 青铜器为什么被铁器取代
古北水镇春节活动:属蛇免票!
十二星座中的属蛇人:十二种独特性格
1965年蛇年人:见证中国60年社会变革
冬游威海:荣成大天鹅的浪漫邂逅
冬日打卡荣成好运角:天鹅大片攻略
打卡荣成天鹅湖:近万只天鹅的冬日盛宴
荣成:一座城市的天鹅保护之路
Win7隐藏文件恢复大揭秘!三种实用解决方案帮你轻松找回"失踪"文件
Win7系统误删文件怎么办?5种实用恢复方法详解
高温烹饪的健康隐患:丙烯酰胺的危害
高温烹饪真的会破坏食物营养吗?
哈佛研究:高温烹饪会增加糖尿病风险,这些健康隐患你可能不知道