uniapp实现页面滑动

本文档展示了使用uniapp实现页面滑动和列表滚动加载更多的具体代码实现,包括滚动视图组件(scoll)、轮播组件(swiper)以及下拉刷新和上拉加载功能。同时,还提供了菜单栏的水平滚动和列表项的详细展示,涵盖了数据获取、事件处理和界面交互等关键部分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个在手机上卡的要死,最好还是使用点击的那种

uniapp实现页面滑动

整体代码

<template>
	<view :style="{height:comHeight-swiperheight-padding+'px'}">
		<scoll :list="scoll" @getIndex="getIndex1" :activeIndex.sync="activeIndex" :index="index" class="padding"
			ref="scoll" />
		<swiper :style="{height:comHeight-swiperheight-padding+'px'}" :current="activeIndex" @change="changeIndex"
			:disable-touch="touch" :duration="durations">
			<block v-for="(item,index) in scoll.length" :key="index">
				<swiper-item>
					<view class="swiper-item padding" :style="{'padding-bottom':padding+10+'px'}" style="height: 100%;">
						<scroll-view scroll-y="true" style="height: 100%;" @scrolltolower="getTaskList" scroll-anchoring
							@refresherrefresh="refresherrefresh" @refresherrestore="refresherrestore"
							@refresherabort="refresherabort" :refresher-triggered="refresherTriggered"
							:refresher-threshold="45" :refresher-enabled="true" refresher-background="#f9f9f9">
							<hotList :list="taskList[index].data" ref="hotList" v-if="taskList[index].hackReset" />
							<view class="u-loadding" v-show="loadding">
								<u-loading mode="flower" size="40" />
							</view>
							<u-divider v-if="(taskList[activeIndex].page-1)* limit >= taskList[activeIndex].totalCount">
								没有更多了</u-divider>
						</scroll-view>
					</view>
				</swiper-item>
			</block>
		</swiper>
	</view>
</template>

<script>
	import scoll from '@/components/scoll/scoll.vue';
	import hotList from '@/components/hotList/hotList.vue';
	export default {
		components: {
			hotList,
			scoll,

		},
		props: {
			isRefresh: Boolean,
			comHeight: Number,
			index: Boolean,
			padding: Number
		},
		data() {
			return {
				refresherTriggered: false,
				_refresherTriggered: false,
				refresher: false,
				refresh: false,
				triggered: false, //是否开启下拉刷新
				more: false, //没有更多了
				label_id: 0,
				durations: 500,
				touch: false,
				touchStart: 0,
				touchMove: 0,
				loadding: false,
				scoll: [{
					id: 0,
					name: '全部',
					type: false
				}],
				swiperheight: 0,
				taskList: [{
					data: [],
					page: 1,
					ctime: '',
					totalCount: 1,
					hackReset: true
				}], //数据列表
				limit: 9, //每页请求的数量
				activeIndex: 0
			}
		},
		watch: {
			isRefresh(res) {
				if (res) {
					this.refresherrefresh()
				}
			}
		},
		mounted() {
			let query = uni.createSelectorQuery().in(this)
			query.select('.padding').boundingClientRect(res => {
				this.swiperheight = res.height
			}).exec()
			this.getCard()
			this.getTaskList()
		},
		methods: {
			// 自定义下拉刷新被触发
			refresherrefresh() {
				let _this = this;
				if (_this._refresherTriggered) {
					return;
				}
				_this._refresherTriggered = true;
				//界面下拉触发,triggered可能不是true,要设为true
				if (!_this.refresherTriggered) {
					_this.refresherTriggered = true;
				}
				this.loadStoreData();
			},
			// 自定义下拉刷新被复位
			refresherrestore() {
				let _this = this;
				_this.refresherTriggered = false;
				_this._refresherTriggered = false;
			},
			// 自定义下拉刷新被中止
			refresherabort() {
				let _this = this;
				_this.refresherTriggered = false;
				_this._refresherTriggered = false;
			},
			loadStoreData() {
				let _this = this;
				_this.taskList[_this.activeIndex] = {
					data: [],
					page: 1,
					ctime: '',
					totalCount: 1,
					hackReset: false
				}
				setTimeout(res => {
					_this.getTaskList("Refresh")
				}, 500)

			},

			// 根据点击跳转相应的标签
			changeSchool() {
				let changeIndex = 0
				let indexID = uni.getStorageSync('type_id') || 0
				this.scoll.forEach((res, index) => {
					if (res.id == indexID) {
						changeIndex = index
					}
				})
				uni.removeStorageSync('type_id')
				this.getIndex1(changeIndex, changeIndex > 0 ? indexID : 0)
			},
			// 获取列表
			getCard() {
				this.$request.register("communication/getTypeList", {
						type: 0,
					}).then((res) => {
						let typeList = [];
						for (let i = 0; i < res.length; i++) {
							this.scoll.push({
								id: res[i].id,
								name: res[i].name,
								type: false,
							});
							this.taskList[i + 1] = {
								data: [],
								page: 1,
								ctime: '',
								totalCount: 1,
								hackReset: true
							}
						}
						setTimeout(res => {
							this.changeSchool()
						}, 500)
					})
					.catch((res) => {
						uni.showToast({
							title: res,
							icon: "none",
						});
					});
			},
			getTaskList() {
				let taskList = this.taskList[this.activeIndex]
				if (this.loadding || (taskList.page - 1) * this.limit >= taskList.totalCount) {
					return
				}

				this.loadding = true
				this.$request.register('task/list', {
					page: taskList.page,
					limit: this.limit,
					query: {
						label_id: this.label_id,
						ctime: taskList.ctime
					},
				}).then(res => {
					if (this.refresherTriggered) {
						this.refresherTriggered = false; //触发onRestore,并关闭刷新图标
						this._refresherTriggered = false;
						uni.showToast({
							title: "刷新成功",
							icon: "none"
						})

					}
					taskList.hackReset = true
					if (taskList.page === 1) {
						taskList.ctime = res.ctime
					}
					taskList.page++;
					taskList.totalCount = res.totalCount
					res.data.forEach(item => {
						taskList.data.push({
							...item
						})
					});
					this.loadding = false
				}).catch(res => {
					this.loadding = false
					uni.showToast({
						title: res,
						icon: 'none'
					})
				})
			},
			// 滑动切换
			changeIndex(res) {
				this.label_id = this.$refs.scoll.changeIndex(res.detail.current)
				this.activeIndex = res.detail.current
				if (this.taskList[this.activeIndex].data.length == 0) {
					this.getTaskList("Refresh")
				}
				this.$refs.scoll.scollChange(res.detail.current)
			},
			// 点击导航切换
			getIndex1(res, item) {
				this.label_id = item
				this.durations = 0
				this.activeIndex = res
				setTimeout(res => {
					this.durations = 500
				}, 30)
			}
		}
	}
</script>


<style scoped>
	.swiper-item {
		height: 100%;
	}

	.padding {
		padding: 0 30rpx;
	}
</style>


菜单部分代码

<template>
	<view >
		<scroll-view scroll-x class="nav-tab-wrap" :throttle="false" @scroll="scrollEvent" scroll-with-animation
			:scroll-left="scrollLeft" >
			<view class="nav-tab">
				<block v-for="(item,index) in list" :key="index">
					<view class="nav-tab-item" :style="index==list.length-1?'margin-right:0;':''" :class="{'active':currentIndex==index}" @tap="changeTab(index,item.id)">{{item.name}}
					</view>
				</block>
				<view class="underline" :style="'left:'+ left +'px;width:'+ width +'px;'"></view>
			</view>
		</scroll-view>
	</view>
</template>
	
<script>
	export default {
		props: {
			list: Array,
			activeIndex: Number  //当前选中的下标
		},
		data() {
			return {
				withs:false,
				currentIndex: 0, //当前选中的索引值
				left: 0, //滑动条左边距离
				width: 0, //滑动条宽度
				scrollX: 0, //滚动条的位置
				space: uni.upx2px(-35), //滑动条和item的左右间距
				scrollLeft: 0, //滚动条到左边的距离
				contentScroll: 0 //滚动条的宽度
			}
		},	
		methods: {
			changeTab(num) {
				let that = this;
				that.currentIndex = num;
				this.scollChange(num)
				this.$emit('getIndex', num,that.list[num].id)
			},
			//用来监听菜单栏下面的横条,还有让菜单栏选中的部分居中
			scollChange(num){
					let that = this;
				let selectorQuery = uni.createSelectorQuery().in(that);
				selectorQuery.selectAll('.nav-tab-item').boundingClientRect(function(data) {
					// data 为当前选中tab的节点信息
					num==0?that.left=0:that.left = data[num].left + that.scrollX + that.space;
					that.width = data[num].width;
				}).exec();
				// 获取滚动条的宽度
				selectorQuery.select('.nav-tab-wrap').boundingClientRect(data => {
					this.contentScroll = data.width
				}).exec()
				this.scrollLeft =parseInt(this.left) - parseInt(this.contentScroll / 2)  + parseInt(that.width / 2) 
				setTimeout(res=>{
					this.scrollLeft =parseInt(this.left) - parseInt(this.contentScroll / 2)  + parseInt(that.width / 2)  //再次刷新下横向滚动条。防止出现手机端不居中的情况
				},100)
			},
			//父组件滑动切换时返回当前菜单的id,用来父组件请求数据
			changeIndex(index){
				this.currentIndex = index;
				return this.list[index].id
					
			},
			scrollEvent(e) {
				this.scrollX = e.detail.scrollLeft;
			}
		}
	}
</script>


<style lang="less">
	.active{border-bottom: 1px solid #FF6100;}
	scroll-view ::-webkit-scrollbar {
		width: 0;
		height: 0;
		background-color: transparent;
	}
	.nav-tab-wrap {
		max-width: 100%;
		white-space: nowrap;
		.nav-tab {
			position: relative;
			.nav-tab-item {
				margin-right: 60rpx;
				line-height: 80rpx;
				display: inline-block;
				color: #989898;
				font-size: 28rpx;
				&.active {
					color: #FF6100;
				}
			}
			.underline {
				position: absolute;
				height: 5rpx;
				background-color: #FF6100;
				bottom: 0;
				transition: 0.2s;
			}
		}
	}
</style>

列表部分代码

<template>
	<view>
		<view class="list">
			<view class="list-list " v-for="(item,index) in Hotlist" :key="index" @tap="jump(item.id)">
				<view class="list-cloumn list-cloumn-margin">
					<view class="list-title ">
						{{item.title}}
					</view>
					<view class="list-price " v-if="$request.money">
						<text>¥</text>{{item.price}}
					</view>
				</view>
				<view class="list-cloumn-second list-cloumn-margin">
					<view class="list-menu" v-for="(res,index) in item.label" :key="index">
						{{res.name}}
					</view>

				</view>
				<view class="list-cloumn-second list-describes list-cloumn-margin">
					{{item.describes}}
				</view>
				<view class="list-cloumn">
					<view>
						<view class="list-address">
							<image src="../../static/many/map1.png" mode=""></image>
							<!-- {{item.address.city}}  -->
							<view class="list-address-text">
								<text v-if="JSON.stringify(item.address)!=='[]'"> {{item.address.district}}</text>
								<text v-else>线上任务</text>
							</view>

						</view>
					</view>
					<view class="list-number">
						<view class="list-endTimer " style="margin-right: 36upx;" v-if="item.end_time">
							{{item.end_time}}前
						</view>
						<view class="list-endTimer list-count"
							:class="item.view_count==item.max_number?'list-endColor':''">
							抢单 {{item.count}}/{{item.max_number}}
						</view>
					</view>
				</view>
			</view>
			<view class="no-arr" v-if="icon">
				<image src="../../static/no-comment.png" mode=""></image>
				<text class="text">没有找到任务呢 <text class="goAdd" @click="goAdd">去发布</text> </text>
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		props: {
			list: {
				type: Array,
				default: []
			}
		},
		data() {
			return {
				loading: true,
				Hotlist: [],
				icon: false
			}
		},
		mounted() {
			if (this.list) {
				this.Hotlist = this.list
			} else {
				this.icon = true
			}
		},
		updated() {
			this.Hotlist = this.list
		},
		methods: {
			// 去发布
			goAdd() {
				uni.navigateTo({
					url: "/pages/elsetask/elsetask"
				})
			},
			jump(id) {
				uni.navigateTo({
					url: "/pages/mission/mission?id=" + id,
					animationType: 'slide-in-bottom',
					animationDuration: 300
				});
			}
		}
	}
</script>

<style scoped>
	.goAdd {
		color: #FF5E00;
		margin-left: 20rpx;
	}

	.list {
		position: relative;
	}

	.no-arr {
		position: absolute;
		left: 50%;
		transform: translateX(-50%);
		top: 100rpx;
		text-align: center;
	}

	.text {
		margin-top: 20rpx;
		display: block;
		color: #989898;
	}

	.no-arr>image {
		width: 554rpx;
		height: 230rpx;
		object-fit: cover;
	}

	.list {
		width: 100%;
	}

	.list-count {
		font-weight: 700;
	}

	.list-list {
		display: flex;
		flex-direction: column;
		margin-top: 20upx;
		justify-content: space-between;
		background: #fff;
		padding: 33upx 32upx;
		border-radius: 13upx;
		box-shadow: 0 3upx 10upx #00000005;
	}

	.list-cloumn {
		display: flex;
		align-items: center;
		justify-content: space-between;
	}

	.list-title {
		width: 80%;
		text-overflow: ellipsis;
		white-space: nowrap;
		overflow: hidden;
		font-weight: 700;
		color: #050F1A;
		font-size: 36upx;
	}

	.list-price>text {
		font-size: 25upx;
	}

	.list-price {
		color: #FF5E00;
		font-size: 40upx;
	}

	.list-cloumn-second {
		display: flex;
		flex-wrap: wrap;

	}

	.list-cloumn-margin {
		margin-bottom: 10rpx;
	}

	.list-describes {
		display: -webkit-box !important;
		overflow: hidden;
		-webkit-line-clamp: 2;
		-webkit-box-orient: vertical;
	}

	.list-menu {
		padding: 8upx 23upx;
		color: #646566;
		font-size: 22upx;
		background-color: #F6F7F8;
		border-radius: 7upx;
		line-height: 1;
		margin-right: 10upx;
		margin-bottom: 10upx;
	}

	.list-address>image {
		width: 36upx;
		height: 36upx;
		margin-right: 13upx;
	}

	.list-address {
		display: flex;
		color: #969799;
		font-size: 24upx;
	}

	.list-address-text {
		color: #969799;
		font-size: 24upx;
	}

	.list-number {
		color: #FF5E00;
		display: flex;
		align-items: center;
	}

	.list-endTimer {
		font-size: 24upx;
	}

	.list-endColor {
		color: #646566 !important;
	}
</style>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值