uniapp实现侧边导航联动效果

功能的核心技术要点:scroll-view作为视图容器,及其属性
scroll-into-view,用于完成左侧点击联动
uni.createSelectorQuery().selectAll();获取右侧所有元素信息,获取top值存入数组,用于计算滑动时需要的联动

实现效果如下
在这里插入图片描述实现代码如下,直接copy,具体样式按需调试

<template>
	<view class="bodys">
		<view class="scroll_box" id="scroll_box">
			<scroll-view :style="{ height: scrollHeight + 'px' }" 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 + 'px' }" @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}`;
			}
		},
		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>

  • 6
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
实现侧边分类导航栏,您需要执行以下步骤: 1.创建一个分类表 您需要创建一个分类表,该表包含分类的名称和对应的ID。您可以使用数据库软件(如MySQL)来创建此表。如下所示: CREATE TABLE categories ( id INT(11) NOT NULL AUTO_INCREMENT, name VARCHAR(50) NOT NULL, PRIMARY KEY (id) ); 2.添加分类数据 在分类表中添加分类数据。如下所示: INSERT INTO categories (name) VALUES ('电子产品'); INSERT INTO categories (name) VALUES ('服装'); INSERT INTO categories (name) VALUES ('家居用品'); 3.在Vue中获取分类数据 使用Vue的axios库来获取分类数据。您可以在uniapp的main.js文件中添加以下代码: import axios from 'axios'; Vue.prototype.$http = axios; Vue.prototype.$http.get('/api/categories') .then(response => { this.categories = response.data; }) .catch(error => { console.log(error); }); 4.在侧边栏中显示分类 在侧边栏中显示分类。您可以使用uniapp的组件来创建侧边栏,如u-slide-menu和u-list组件。您可以在侧边栏中使用v-for指令来遍历分类数据,然后将每个分类显示为列表项。如下所示: <u-slide-menu :open.sync="open"> <u-list> <u-list-item v-for="category in categories" :key="category.id"> {{ category.name }} </u-list-item> </u-list> </u-slide-menu> 5.显示分类的产品 当用户单击分类时,显示该分类的产品。您可以在分类表中添加产品数据,并将产品与分类关联。然后,在单击分类时,使用axios来获取该分类的产品数据,并显示该数据。如下所示: methods: { onCategoryClick(category) { this.$http.get(`/api/categories/${category.id}/products`) .then(response => { this.products = response.data; }) .catch(error => { console.log(error); }); } } 以上是实现侧边分类导航栏的基本步骤。您可以将其扩展以满足您的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值