uniapp实现楼层导航 ,滚动定位,锚点导航

uniapp实现楼层导航的核心技术要点:

1、scroll-view作为视图容器,

2、用其属性scroll-into-view,用于完成点击联动

uniapp实现楼层导航 ,滚动定位,锚点导航_第1张图片

3、uni.createSelectorQuery().selectAll();获取右侧所有元素信息,获取top值存入数组,用于计算滑动时需要的联动

uniapp实现楼层导航 ,滚动定位,锚点导航_第2张图片
代码示例(可直接复制查看)

<template>
	<view class="bodys">
		<view class="scroll_box" id="scroll_box">
			<scroll-view :style="{ height: scrollHeight + 'rpx' }" scroll-y='true' class="left_box"
				:scroll-into-view="leftIntoView">
				<view class="left_item" v-for="(item,i) in leftArray" :key='i' @click="onLeft" :data-index="i"
					:id="'left-'+i" :class="{select:i == leftIndex}">
					{{item}}
				</view>
			</scroll-view>
			<scroll-view :style="{ height: scrollHeight + 'rpx' }" @scroll="mainScroll" :scroll-into-view="scrollInto"
				scroll-y='true' class="right_box" scroll-with-animation="true">
				<slot></slot>
				<view class="right_item" v-for="(item,i) in rightArray" :key='i' :id="'item-'+i">
					<view class="rigth_title">
						{{item.title}}
					</view>
					<view class="lis" v-for="(items,j) in item.list" :key='j'>
						{{items}}
					</view>
				</view>
				<view class="fill-last" :style="{ height: fillHeight + 'px' }"></view>
			</scroll-view>
		</view>
	</view>
</template>

<script>
	export default {
		name: "side-navigation",
		data() {
			return {
				leftArray: [],
				rightArray: [],
				scrollHeight: 400,
				scrollInto: "",
				leftIndex: 0,
				topArr: [],
				scrollTopSize: 0,
				fillHeight: 0, // 填充高度,用于最后一项低于滚动区域时使用
			}
		},
		computed: {
			/* 计算左侧滚动位置定位 */
			leftIntoView() {
				return `left-${this.leftIndex > 3 ? this.leftIndex - 3 : 0}`;
				//return `left-${this.leftIndex}`;	//根据实际情况
			}
		},
		mounted() {
			/* 等待DOM挂载完成 */
			this.$nextTick(() => {
				/* 在非H5平台,nextTick回调后有概率获取到错误的元素高度,则添加200ms的延迟来减少BUG的产生 */
				setTimeout(() => {
					/* 等待滚动区域初始化完成 */
					this.initScrollView().then(() => {
						/* 获取列表数据,你的代码从此处开始 */
						this.getListData();		//根据实际情况  用时换成自己的或注释
					});
				}, 200);
			});
		},
		methods: {
			/* 初始化滚动区域 */
			initScrollView() {
				return new Promise((resolve, reject) => {
					let view = uni.createSelectorQuery().select('#scroll_box');
					view.boundingClientRect(res => {
						console.log(res);
						this.scrollTopSize = res.top;
						this.scrollHeight = res.height;	//根据实际情况来赋值
						this.$nextTick(() => {
							resolve();
						});
					}).exec();
				});
			},
			// 获取数据
			getListData() {
				new Promise((resolve, reject) => {
					uni.showLoading();
					setTimeout(() => {
						let [left, main] = [
							[],
							[]
						];

						for (let i = 0; i < 25; i++) {
							left.push(`${i + 1}类商品`);

							let list = [];
							let r = Math.floor(Math.random() * 10);
							r = r < 1 ? 3 : r;
							for (let j = 0; j < r; j++) {
								list.push(j);
							}
							main.push({
								title: `第${i + 1}类商品标题`,
								list
							});
						}

						// 将请求接口返回的数据传递给 Promise 对象的 then 函数。
						resolve({
							left,
							main
						});
					}, 1000);
				}).then(res => {
					uni.hideLoading();
					this.leftArray = res.left;
					this.rightArray = res.main;
					// DOM 挂载后 再调用 getElementTop 获取高度的方法。
					this.$nextTick(() => {
						this.getElementTop();
					});
				});
			},
			// 获取元素顶部信息
			getElementTop() {
				new Promise((resolve, reject) => {
					let view = uni.createSelectorQuery().selectAll('.right_item');
					view.boundingClientRect(data => {
						resolve(data);
					}).exec();
				}).then(res => {
					console.log(res);
					let topArr = res.map(item => {
						return item.top - this.scrollTopSize; /* 减去滚动容器距离顶部的距离 */
					});
					this.topArr = topArr;

					/* 获取最后一项的高度,设置填充高度。判断和填充时做了 +-20 的操作,是为了滚动时更好的定位 */
					let last = res[res.length - 1].height;
					if (last - 20 < this.scrollHeight) {
						this.fillHeight = this.scrollHeight - last + 20;
					}
				});
			},
			// 点击左侧导航
			onLeft(e) {
				const index = e.currentTarget.dataset.index;
				// this.leftIndex = index
				this.scrollInto = `item-${index}`
			},
			// 右侧滑动
			mainScroll(e) {
				let top = e.detail.scrollTop;
				let index = 0;
				/* 查找当前滚动距离 */
				for (let i = this.topArr.length - 1; i >= 0; i--) {
					/* 在部分安卓设备上,因手机逻辑分辨率与rpx单位计算不是整数,滚动距离与有误差,增加2px来完善该问题 */
					if (top + 2 >= this.topArr[i]) {
						index = i;
						break;
					}
					
				}
				this.leftIndex = index < 0 ? 0 : index;
			},
		},

	}
</script>

<style>
	page,.bodys {
		height: 100%;
	}

	.scroll_box {
		display: flex;
		height: 100%;
	}

	.left_box {
		width: 30%;
	}

	.left_item {
		height: 80rpx;
	}

	.lis {
		height: 200rpx;
		border-radius: 10rpx;
		background: #808080;
		color: #FFFFFF;
		text-align: center;
		line-height: 200rpx;
		margin-bottom: 10rpx;
	}

	.select {
		background-color: #4CD964;
	}
</style>


实际实战

组件并不是顶高(不占全屏)
scrollHeight 为内容最大高度,高度动态适配

onLoad(){
	//获取系统信息,获取手机高度。单位为'rpx'
	
	uni.getSystemInfo({
		success: (result) => {
			// console.log(result)
			this.navHeight = result.statusBarHeight * (750 / result.windowWidth) + 88
			this.scrollHeight = 2*result.windowHeight-yHeight-this.navHeight;
		}
	})
	scrollHeight 滚动条里内容高度
	windowHeight 获取到的手机高度
	yHeight 在滚动条上方的高度(如果下方也有内容,也要加上)
	navHeight 自定义导航栏高度
	
	
}

uniapp实现楼层导航 ,滚动定位,锚点导航_第3张图片
页面生命周期 onPageScroll()
监听页面滚动 页面在垂直方向已滚动的距离(单位px)
根据需求写

//页面生命周期  
//监听页面滚动   页面在垂直方向已滚动的距离(单位px)
onPageScroll(e) {
	this.scrollTop = e.scrollTop;
	// console.log(e);
	
	if(e.scrollTop>100){
		this.params.opacity=1
		this.colors='#281F14'
	}else{
		this.params.opacity=0
		this.colors='#ffffff'
	}
}

右侧滑动时

mainScroll(e) {
	let top = e.detail.scrollTop;
	// console.log(e)
	let index = 0;
	/* 查找当前滚动距离 */
	for (let i = this.topArr.length - 1; i >= 0; i--) {
		// console.log(i)
		// console.log(this.topArr)
		// console.log(this.topArr[i])
		/* 滚动距离与系统高度有误差,可以增加第二层楼栋的高度,再减去1,来完善该问题 */
		if ((top + this.topArr[1]-1) >= this.topArr[i]) {
			index = i;
			break;
		}
	}
	// console.log(index)
	this.leftIndex = index < 0 ? 0 : index;
}

scroll-view右侧滚动条高度:   如果楼层高度小于固定高度,就显示楼层高度。否则就显示固定高度
let a=uni.getStorageSync('Heights')
let b=50*this.indexList.length
if(this.Heights>b){
	this.Heights=50*this.indexList.length
}else{
	this.Heights=uni.getStorageSync('Heights')
}

uniapp参考
还有一些vue和原生js参考,以后用到可以参考。
vue参考
原生态JS实现楼层导航案例

你可能感兴趣的:(uniapp,uni-app,前端,javascript,vue.js,html)