uniapp 顶部标题吸顶并横向滚动,内容滚动,内容与标题关联滚动

 

要求:

1. 顶部标题滚动,点击标题自动滚动到中间

2. 点击标题,定位到特定内容

3. 内容滚动,标题跟随

某大佬文章内容  uni-app scroll-view 点击实现元素居中?_uni-app vue3 scrollview getscrollw-CSDN博客

思路:使用scroll-view   scroll-left (设置横向滚动条的位置,也可以使用 scroll-into-view,但是有固定标题时,滚上去的内容总是被遮挡一部分 )  scroll-with-animation(设置过渡动画)

<template>
	<view style="">
		<image src="https://img2.baidu.com/it/u=4017416575,2916339385&fm=253&fmt=auto&app=138&f=JPEG?w=681&h=360"
			style="width: 100%;vertical-align: bottom;" mode="widthFix"></image>
		<u-sticky>  <!--uview 吸顶组件 就不用自己写固定定位了-->
			<scroll-view :scroll-x="true" class="tab-title" :scroll-left="scrollLeft" scroll-with-animation>
				<view :class="{'tab-title-item':true,'active':type===index}" @click="switchType(index)"
					v-for="(item,index) in titleList" :key="index">
					{{item.label}}
				</view>
			</scroll-view>
		</u-sticky>
		<view>
			<view v-for="(val,index) in pinleiList" :key="index" :id="'target'+index" class="goods-content-item">
				<view class="title ">
					{{val.label}}
				</view>
				<view class="item-content" :style="{'background-color':val.bgc}">
					<view class="goods">
						<view class="goods-item" v-for="(item,index) in val.goods" :key="index">
							<view style="position: relative;">
								<u-lazy-load threshold="-300" border-radius="10" :image="item.imgurl" :index="index"></u-lazy-load>
							</view>

						</view>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<template>
	<view style="">
		<image src="https://img2.baidu.com/it/u=4017416575,2916339385&fm=253&fmt=auto&app=138&f=JPEG?w=681&h=360"
			style="width: 100%;vertical-align: bottom;" mode="widthFix"></image>
		<u-sticky>
			<scroll-view :scroll-x="true" class="tab-title" :scroll-left="scrollLeft" scroll-with-animation>
				<view :class="{'tab-title-item':true,'active':type===index}" @click="switchType(index)"
					v-for="(item,index) in titleList" :key="index">
					{{item.label}}
				</view>
			</scroll-view>
		</u-sticky>
		<view>
			<view v-for="(val,index) in pinleiList" :key="index" :id="'target'+index" class="goods-content-item">
				<view class="title ">
					{{val.label}}
				</view>
				<view class="item-content" :style="{'background-color':val.bgc}">
					<view class="goods">
						<view class="goods-item" v-for="(item,index) in val.goods" :key="index">
							<view style="position: relative;">
								<u-lazy-load threshold="-300" border-radius="10" :image="item.imgurl" :index="index"></u-lazy-load>
							</view>

						</view>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	const pinleiList = [{
			label: "风景1",
			bgc: '#FF8C50', // 默认背景色,可以不写,除非需要改颜色

			goods: [ //商品
				{
					imgurl: 'https://img0.baidu.com/it/u=631814769,3587830013&fm=253&fmt=auto?w=200&h=200'
				},
				{
					imgurl: 'https://img0.baidu.com/it/u=631814769,3587830013&fm=253&fmt=auto?w=200&h=200'
				},
				{
					imgurl: 'https://img0.baidu.com/it/u=631814769,3587830013&fm=253&fmt=auto?w=200&h=200'
				},
				{
					imgurl: 'https://img0.baidu.com/it/u=631814769,3587830013&fm=253&fmt=auto?w=200&h=200'
				}

			]
		},
		{
			label: "风景2",
			bgc: '#50d8ff',
			goods: [ //商品
				{
					imgurl: 'https://img1.baidu.com/it/u=1048813378,1100765611&fm=253&fmt=auto&app=138&f=JPEG?w=190&h=190'
				},
				{
					imgurl: 'https://img1.baidu.com/it/u=1048813378,1100765611&fm=253&fmt=auto&app=138&f=JPEG?w=190&h=190'
				},
				{
					imgurl: 'https://img1.baidu.com/it/u=1048813378,1100765611&fm=253&fmt=auto&app=138&f=JPEG?w=190&h=190'
				},
				{
					imgurl: 'https://img1.baidu.com/it/u=1048813378,1100765611&fm=253&fmt=auto&app=138&f=JPEG?w=190&h=190'
				}

			]
		},
		{
			label: "风景3",
			bgc: '#FF8C50',
			goods: [ //商品
				{
					imgurl: 'https://img1.baidu.com/it/u=4253149046,3580800107&fm=253&fmt=auto&app=120&f=JPEG?w=200&h=200'
				},
				{
					imgurl: 'https://img1.baidu.com/it/u=4253149046,3580800107&fm=253&fmt=auto&app=120&f=JPEG?w=200&h=200'
				},
				{
					imgurl: 'https://img1.baidu.com/it/u=4253149046,3580800107&fm=253&fmt=auto&app=120&f=JPEG?w=200&h=200'
				},
				{
					imgurl: 'https://img1.baidu.com/it/u=4253149046,3580800107&fm=253&fmt=auto&app=120&f=JPEG?w=200&h=200'
				}

			]
		},
		{
			label: "风景4",
			bgc: '#FF8C50',
			goods: [ //商品
				{
					imgurl: 'https://img2.baidu.com/it/u=1762261007,2519826657&fm=253&fmt=auto&app=138&f=JPEG?w=200&h=200'
				},
				{
					imgurl: 'https://img2.baidu.com/it/u=1762261007,2519826657&fm=253&fmt=auto&app=138&f=JPEG?w=200&h=200'
				},
				{
					imgurl: 'https://img2.baidu.com/it/u=1762261007,2519826657&fm=253&fmt=auto&app=138&f=JPEG?w=200&h=200'
				},
				{
					imgurl: 'https://img2.baidu.com/it/u=1762261007,2519826657&fm=253&fmt=auto&app=138&f=JPEG?w=200&h=200'
				}

			]
		},
		{
			label: "风景5",
			bgc: '#FF8C50',
			goods: [ //商品
				{
					imgurl: 'https://img2.baidu.com/it/u=1084408498,2948431230&fm=253&fmt=auto&app=138&f=JPEG?w=130&h=170'
				},
				{
					imgurl: 'https://img2.baidu.com/it/u=1084408498,2948431230&fm=253&fmt=auto&app=138&f=JPEG?w=130&h=170'
				},
				{
					imgurl: 'https://img2.baidu.com/it/u=1084408498,2948431230&fm=253&fmt=auto&app=138&f=JPEG?w=130&h=170'
				},
				{
					imgurl: 'https://img2.baidu.com/it/u=1084408498,2948431230&fm=253&fmt=auto&app=138&f=JPEG?w=130&h=170'
				}

			]
		},
		{
			label: "风景6",
			bgc: '#FF8C50',
			goods: [ //商品
				{
					imgurl: 'https://img0.baidu.com/it/u=2414855935,1287564153&fm=253&fmt=auto&app=138&f=JPEG?w=200&h=200'
				},
				{
					imgurl: 'https://img0.baidu.com/it/u=2414855935,1287564153&fm=253&fmt=auto&app=138&f=JPEG?w=200&h=200'
				},
				{
					imgurl: 'https://img0.baidu.com/it/u=2414855935,1287564153&fm=253&fmt=auto&app=138&f=JPEG?w=200&h=200'
				},
				{
					imgurl: 'https://img0.baidu.com/it/u=2414855935,1287564153&fm=253&fmt=auto&app=138&f=JPEG?w=200&h=200'
				}

			]
		},
		{
			label: "风景7",
			bgc: '#FF8C50',
			goods: [ //商品
				{
					imgurl: 'https://img2.baidu.com/it/u=652299287,3144977570&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1372'
				},
				{
					imgurl: 'https://img2.baidu.com/it/u=652299287,3144977570&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1372'
				},
				{
					imgurl: 'https://img2.baidu.com/it/u=652299287,3144977570&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1372'
				},
				{
					imgurl: 'https://img2.baidu.com/it/u=652299287,3144977570&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1372'
				}

			]
		},
	]


	export default {
		data() {
			return {
				pinleiList,
				type: 0,
				titleList: [],
				contentScrollW: 0, // 导航区宽度
				curIndex: 0, // 当前选中
				scrollLeft: 0, // 横向滚动条位置
				scrollTop: 0,   // 滚动出去的距离
			}
		},
		onReady() {
			
			this.titleList = pinleiList.map(item => {
				return {
					label: item.label
				}
			})
			this.$nextTick(() => {
				this.getScrollW();
			})

		},
		// 滚动条滚动触发
		onPageScroll(e) {
			// e.scrollTop 表示当前页面滚动的距离
			this.scrollTop = e.scrollTop
			this.updateTitle()   
		},
		onLoad() {
			// 进入页面就滚动到顶部
			uni.pageScrollTo({
				scrollTop: 0
			});
		},
		methods: {
			updateTitle() {
				const query = uni.createSelectorQuery().in(this);
				query.selectAll('.goods-content-item').boundingClientRect((data) => {
					let dataLen = data.length;
					for (let i = 0; i < dataLen; i++) {
						// 找到此时在可视区域内的 部分 ,这里去除了固定栏高度 更新标题
						if (data[i].top <= this.tabTitleHeight && data[i].bottom > 0) {
							this.type = i;
							this.scrollLeft = this.titleList[i].left - this.contentScrollW / 2 + this.titleList[i].width / 2;
						}
					}

				}).exec();
			},
			getScrollW() {
				const query = uni.createSelectorQuery().in(this);

				query.select('.tab-title').boundingClientRect(data => {
					// 拿到 scroll-view 组件宽度
					this.contentScrollW = data.width
					this.tabTitleHeight = data.height
				}).exec();

				query.selectAll('.tab-title-item').boundingClientRect(data => {
					let dataLen = data.length;
					for (let i = 0; i < dataLen; i++) {
						//  scroll-view 子元素组件距离左边栏的距离
						this.titleList[i].left = data[i].left;
						//  scroll-view 子元素组件宽度
						this.titleList[i].width = data[i].width

					}

				}).exec()
			},
			switchType(index) {
				this.type = index;
				this.scrollLeft = this.titleList[index].left - this.contentScrollW / 2 + this.titleList[index].width / 2;
				this.scrollToTop()
			},
			// 滚动到顶部
			scrollToTop() {
				const query = uni.createSelectorQuery().in(this);

				query.select('#target' + this.type).boundingClientRect(data => {
					uni.pageScrollTo({
						// 距离顶部的高度 + 已滚动高度 - 固定标题栏高度  (如果不减去标题栏高度,总是有一部分会被遮挡)
						scrollTop: data.top + this.scrollTop - this.tabTitleHeight,
						duration: 200
					});
				}).exec();
			},
		}
	}
</script>

<style scoped>
	.tab-title {
		background: #F7F7F7;
		white-space: nowrap;
		padding: 0 30rpx;
		box-sizing: border-box;

	}

	.tab-title-item {
		display: inline-block;
		height: 84rpx;
		line-height: 84rpx;

		font-weight: 400;
		font-size: 35rpx;
		color: #666666;
		margin-right: 28rpx;
	}

	.tab-title-item.active {
		border-bottom: 4rpx solid #EB1313;
		color: #EB1313;
	}


	.title {
		padding: 32rpx 18rpx;
		font-weight: bold;
		font-size: 33rpx;
		color: #363636;
		position: relative;
		margin: 0 22rpx;
	}

	.title::before {
		content: "";
		width: 7rpx;
		height: 51rpx;
		background: #EB1313;
		border-radius: 3rpx;
		position: absolute;
		left: 0;
		top: 50%;
		transform: translateY(-50%);
	}

	.item-content {
		margin: 0 22rpx;
		background: #FF8C50;
		border-radius: 10rpx;
		padding: 16rpx 16rpx 0 16rpx;
	}

	.goods {
		width: 100%;
		display: flex;
		flex-wrap: wrap;
		justify-content: space-between;
	}

	.goods-item {
		width: 49%;
		background-color: #fff;
		border-radius: 10rpx;
		margin-bottom: 20rpx;
	}


</style>
<style scoped>
	.tab-title {
		background: #F7F7F7;
		white-space: nowrap;
		padding: 0 30rpx;
		box-sizing: border-box;

	}

	.tab-title-item {
		display: inline-block;
		height: 84rpx;
		line-height: 84rpx;

		font-weight: 400;
		font-size: 35rpx;
		color: #666666;
		margin-right: 28rpx;
	}

	.tab-title-item.active {
		border-bottom: 4rpx solid #EB1313;
		color: #EB1313;
	}


	.title {
		padding: 32rpx 18rpx;
		font-weight: bold;
		font-size: 33rpx;
		color: #363636;
		position: relative;
		margin: 0 22rpx;
	}

	.title::before {
		content: "";
		width: 7rpx;
		height: 51rpx;
		background: #EB1313;
		border-radius: 3rpx;
		position: absolute;
		left: 0;
		top: 50%;
		transform: translateY(-50%);
	}

	.item-content {
		margin: 0 22rpx;
		background: #FF8C50;
		border-radius: 10rpx;
		padding: 16rpx 16rpx 0 16rpx;
	}

	.goods {
		width: 100%;
		display: flex;
		flex-wrap: wrap;
		justify-content: space-between;
	}

	.goods-item {
		width: 49%;
		background-color: #fff;
		border-radius: 10rpx;
		margin-bottom: 20rpx;
	}


</style>

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值