学无先后,达者为师

网站首页 编程语言 正文

uniApp实现滚动视图点击锚点跳转、点击左侧分栏时右侧对应内容置顶、左右分栏联动、getSystemInfo、$nextTick、createSelectorQuery、selectAll

作者:web半晨 更新时间: 2022-06-06 编程语言


1、html部分

<template>
	<view>
		<view class="left_right_column_box">
			<view class="left_column">
				<scroll-view :style="{height: viewHeight}" scroll-y="true" :scroll-top="scrollTop">
					<view v-for="item in titleContenData" :key="item.id"
						:class="{'left_column_for': true, activity: selectIndex==item.index?true:false}"
						@click="clickTitle(item)">
						{{item.title}}
					</view>
				</scroll-view>
			</view>

			<view class="right_column">
				<scroll-view :style="{height: viewHeight}" scroll-y="true" :scroll-into-view="selectId"
					scroll-with-animation="true" @scroll="scroll">
					<view :id="item.id" class="floorType right_title_content_for" v-for="item in titleContenData"
						:key="item.id">
						<view class="right_title">{{item.title}}</view>
						<view v-for="items in item.contents" :key="items.id">{{items.content}}</view>
					</view>
				</scroll-view>
			</view>
		</view>
	</view>
</template>

2、JavaScript部分

// 防抖
let timer = undefined;

export default {
	data() {
		return {
			// 屏幕高度
			viewHeight: null,
			// 源数据
			titleContenData: [],
			// 设置锚点
			selectId: 'id1',
			// 设置高亮
			selectIndex: 0,
			// 设置左栏顶部距离
			scrollTop: 0,
		}
	},

	mounted() {
		let that = this;
		uni.getSystemInfo({
			success: function({
				windowHeight
			}) {
				that.viewHeight = windowHeight + 'px';
			}
		});

		// 创建数据
		that.createData();

		// 此处使用$nextTick是非常有必要
		// 官方建议
		// 实际测试如果不用会报错
		that.$nextTick(function() {
			const query = uni.createSelectorQuery().in(that);

			query.selectAll('.floorType').boundingClientRect(VNodeAll => {
				VNodeAll.forEach(({
					top
				}, i) => {
					// 获取并存储每个视图到顶部的距离
					this.titleContenData[i].viewTop = top;
				});
			}).exec();

			console.log('titleContenData:', this.titleContenData);
		});
	},

	methods: {
		// 滚动时触发
		scroll({
			detail: {
				scrollTop
			}
		}) {
			let that = this,
				titleContenData = that.titleContenData;

			// 防抖
			// timer定义在全局
			// 如果没有防抖会触发许多次
			// 对性能不友好
			if (timer !== undefined) clearTimeout(timer);

			timer = setTimeout(function() {
				// 当右侧滚动到顶部时强制赋值为0
				// 因为在滚动时一般获取到的数据是0-10的范围
				// 小概率会获取到0
				// 因为原先存储viewTop属性的第一个值就是0
				scrollTop = scrollTop < 10 ? 0 : scrollTop;
				let selectIndex = titleContenData.findIndex((item) => item.viewTop >= scrollTop);
				console.log('scrollTop:', scrollTop);
				// 设置高亮
				that.selectIndex = selectIndex;
				// 此属性联动左侧滚动条
				// 当右侧滚动时
				// 左侧也会相应的滚动
				// 只是滚动的距离不一样
				that.scrollTop = 5 * that.selectIndex;
			}, 70);
		},

		// 标题点击事件
		clickTitle({
			id,
			index
		}) {
			console.log(id, index);
			// 设置锚点
			this.selectId = id;
			// 设置高亮
			this.selectIndex = index;
		},

		// 生成内容
		createContent(n) {
			let content = [];
			for (let i = 0; i < n; i++) content.push({
				id: i + 1,
				content: `内容${i+1}内容`
			});
			return content;
		},

		// 创建数据
		createData() {
			// 生成标题
			for (let i = 0; i < 24; i++) this.titleContenData.push({
				// 因为需要绑定id作为锚点目标
				// 所以不能以数字开头
				id: `id${i+1}`,
				index: i,
				title: '标题' + (i + 1),
				contents: this.createContent(parseInt(Math.random() * 24 + 1, 10))
			})
		}
	},
}

3、css部分

/* 公共样式 */
.left_right_column_box {
	width: 100%;
	display: flex;
	justify-content: space-evenly;
}

/* 左侧样式 */
.left_column {
	flex: 1;
}

.left_column_for {
	text-align: center;
	padding: 10rpx 0;
}

.activity {
	color: #000fff;
}

/* 右侧样式 */
.right_column {
	flex: 3;
	margin-left: 36rpx;
}

.right_title_content_for {
	margin-top: 36rpx;
}

.right_title_content_for:first-child {
	margin-top: 0;
}

.right_title {
	font-weight: 700;
}

/* 隐藏scroll-wiew元素的滚动条 */
scroll-view ::-webkit-scrollbar {
	width: 0;
	height: 0;
	background-color: transparent;
}

原文链接:https://blog.csdn.net/weixin_51157081/article/details/124070377

栏目分类
最近更新