uniapp多个标题滑动吸顶效果

需求是模仿支付宝的账单做title吸顶效果
在这里插入图片描述

1.已知吸顶内容及数量
2.需要吸顶的title数量未知,触底加载新的一月数据,则会增加一个title

第一种情况已知标题数量
主要思路:1.获取所有需要吸顶的节点 2.获取每个标题的offsetTop 3.监听滚动位置,为标题的吸顶设置一个显示范围

<view
	class="month-list"
	:style="{ width: '100%', height: '100%' }"	
	ref="scroll"
	>
	  <view style="width:100%;height:100%">
		  <view v-for="(item, index) in dataList" :key="index" class="main">
				<!-- 头部吸顶部分 -->
				<view :class="['common', 'flex-between', 'main-title', item.scrollIndex == index ? 'sticky': '']">
					<view class="semibold text-333" @click="changeMonth(item)">
						<text class="text64">{{item.onlyMonth}}</text>
						<text class="text30" style="margin-left:8rpx;position:relative;top:-4rpx"></text>
						<u-icon :name="item.flag?'arrow-up-fill':'arrow-down-fill'" size="20" class="icon"></u-icon>
					</view>
					<view class="text-666" style="position:relative;top:8rpx">{{item.type?'支出':'收入'}} ¥{{item.income}}</view>
				</view>
				<view class="line-grey" v-if="!isSticky"></view>
				<!-- 月内列表 -->
				<view class="receive-list" v-for="(i,idx) in item.dayList" :key="idx" @click="toDetail" hover-class="receive-list-hover">
					<view class="flex-between-top">
						<!-- <view class="avator"> -->
						<image :src="i.payerImg" class="avator"></image>
						<!-- </view> -->
						<view class="right flex-between text-333">
							<view class="right-left flex-column-between-left text-999">
								<text class="text30 text-333">{{i.type?'向':'收到'}}*{{item.payerGender==1?'先生':'女士'}}</text>
								<text class="text26" style="margin-top:8rpx">{{item.moneyType?'提现':'工程款'}}</text>
								<text class="text26" style="margin-top:8rpx" v-if="i.today">{{i.today}} {{i.payTime | formatStamp('hh:mm')}}</text>
								<text class="text26" style="margin-top:8rpx" v-else-if="i.ystd">{{i.ystd}}  {{i.payTime | formatStamp('hh:mm')}}</text>
								<text class="text26" style="margin-top:8rpx" v-else>{{i.payTime | formatStamp('MM.dd hh:mm')}}</text>
							</view>
							<view class="right-right ubuntu text36">+{{i.money}}</view>
						</view>
					</view>
				</view>
		  </view>
	  </view>
</view>
data(){
	return{
		selectorQuery: {}, // Uniapp SelectorQuery 对象实例
		mainTitleEles: [], // 所有mainTitle标题对象集合
		mainEles: [], // 所有板块对象集合
		ot: [], //存储每个标题的offsetTop
		len: 0, // 标题的个数
		searchBottomY: 0, // 搜索view底部距离页面顶部的距离
		dataList: [
            {
                "month": "2021-08",
                "income": 55.50,
				"expend": 0,
				"scrollIndex": 10,
                "dayList": [
                    {
                        "id": 1,
                        "payerName": "王星星",
                        "payerImg": "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png",
                        "payeeName": "李四",
                        "payeeImg": "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png",
                        "type": 0,
                        "moneyType": 0,
                        "money": 55.50,
                        "payTime": 1629734400000
					},
					//这里自行复制几份
                ]
			},
			{
                "month": "2021-07",
                "income": 55.50,
				"expend": 0,
				"scrollIndex": 0,
                "dayList": [
                    {
                        "id": 9,
                        "payerName": "王星星",
                        "payerImg": "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png",
                        "payeeName": "李四",
                        "payeeImg": "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png",
                        "type": 0,
                        "moneyType": 0,
                        "money": 55.50,
                        "payTime": 1629699870000
					},
					//这里自行复制几份
                ]
            }
		]
	}
},
mounted(){
	// 一定要写在mounted钩子函数中,在这之前页面数据及渲染还没完成,获取不到元素信息会报错
	// 获取 SelectorQuery 对象实例。可以在这个实例上使用 select 等方法选择节点 
	this.selectorQuery = uni.createSelectorQuery().in(this);
	this.initFixedTop()
},
/**
* 监听页面滑动事件
*/
onPageScroll(mescroll) {
	const st = mescroll.scrollTop;
	for (let i = 0; i < this.len; i++) {
		// 滚动时监听位置,为标题的吸顶设置一个显示范围
		// if (st > this.ot[i] && st < this.ot[i + 1]) {
		if (st > this.ot[i] && st < this.ot[i + 1]) {
			this.dataList[i].scrollIndex = i
		} else {
			this.dataList[i].scrollIndex = i + 1//+1是为了保持与上面不一样
		}
	}
},
initFixedTop() {
	this.mainTitle = this.selectorQuery.selectAll('.main-title');
	// 获取所有需要吸顶效果的标题
	uni.createSelectorQuery().selectAll('.main-title').fields({
		rect: true,
		dataset: true
	}, res => {
		this.mainTitleEles = res;
		// 标题的个数
		this.len = this.mainTitleEles.length;
		if(this.len > 0){
			for (let i = 0; i < this.len; i++) {
				this.ot.push(this.mainTitleEles[i].top); //获取每个标题的offsetTop
			}
			// 获取所有需要吸顶的板块
			uni.createSelectorQuery().selectAll('.main').fields({
				rect: true,
				dataset: true,
				size: true
			}, res => {
				this.mainEles = res;
				// 存储每个标题的offsetTop(只读属性,返回当前元素相对于其 offsetParent 元素的顶部内边距的距离)
				// 加上 最后一个吸顶板块的高度. 解决滚动到最后一个标题(i)时,无法获取(i+1)的offsetTop
				this.ot.push(this.mainEles[this.len - 1].top + this.mainEles[this.len - 1].height);
			}).exec();
		} 
	}).exec();
}
.month-list{
	.common{
		height: 140rpx;
		padding: 0 40rpx;
	}
	.sticky{
		width: 100%;
		position: -webkit-sticky;
		position: sticky;
		top: 0rpx;
		background-color: #F3F3F7;
		z-index: 999;
	}
	.receive-list{
		padding: 30rpx 40rpx 0 40rpx;
		.avator{
			width: 72rpx;
			height: 72rpx;
			border-radius: 50%;
		}
		.right{
			flex: 1;
			margin-left: 20rpx;
			.right-right{
				margin-right: 4rpx;
			}
		}
	}
	.icon{
		position: relative;
		top: -4rpx;
		left: 8rpx;
	}
	/* 顶边散开 */
	.flex-between {
		display: flex;
		justify-content: space-between;
		align-items: center;
	}
	.flex-between-top {
		display: flex;
		justify-content: space-between;
		align-items: flex-start;
	}
	.flex-column-between-left {
		display: flex;
		justify-content: space-between;
		align-items: flex-start;
		flex-direction: column;
	}
}

以上参考的:https://evestorm.github.io/posts/7733/

第二种情况后期更新…

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值