uview-plus中二级菜单左右联动更改为uni-app+vue3+vite写法

uview-plus3.0重磅发布,全面的Vue3移动组件库

该插件使用的vue2写法,但支持vue3引用,在此基础上修改为uni-app+vue3+vite;

<template>
	<view class="u-wrap mainClass">
		<!-- <back-header :title="pageTitle" :back-text="backText"></back-header> -->
		<view class="u-search-box">
				<view class="u-search-inner">
				<u-icon name="search" color="#909399" :size="28"></u-icon>
				<text class="u-search-text">搜索</text>
			</view>
		</view>
		<view class="u-menu-wrap">
			<scroll-view scroll-y scroll-with-animation class="u-tab-view menu-scroll-view" :scroll-top="scrollTop"
				:scroll-into-view="itemId">
				<view v-for="(item,index) in tabbar" :key="index" class="u-tab-item"
					:class="[current == index ? 'u-tab-item-active' : '']" @tap.stop="swichMenu(index)">
					<text class="u-line-1">{{item.name}}</text>
				</view>
			</scroll-view>
			<scroll-view :scroll-top="scrollRightTop" scroll-y scroll-with-animation class="right-box"
				@scroll="rightScroll">
				<view class="page-view">
					<view class="class-item" :id="'item' + index" v-for="(item , index) in tabbar" :key="index">
						<view class="item-title">
							<text>{{item.name}}</text>
						</view>
						<view class="item-container">
							<view class="thumb-box" v-for="(item1, index1) in item.foods" :key="index1">
								<image class="item-menu-image" :src="item1.icon" mode=""></image>
								<view class="item-menu-name">{{item1.name}}</view>
							</view>
						</view>
					</view>
				</view>
			</scroll-view>
		</view>
	</view>
</template>
<script lang="ts" setup>
	// import BackHeader from '../../../components/publicNavbar.vue';
	import { defineComponent, ref, onMounted, onBeforeUnmount, getCurrentInstance } from 'vue';
	import classifyData from '@/common/classify.data.js';

	const scrollTop = ref(0);
	const oldScrollTop = ref(0);
	const current = ref(0);
	const menuHeight = ref(0);
	const menuItemHeight = ref(0);
	const itemId = ref('');
	const tabbar = classifyData;
	const menuItemPos = ref([]);
	const arr = ref([]);
	const scrollRightTop = ref(0);
	let timer : NodeJS.Timeout | null = null;
	const pageTitle = ref('商品')
	const backText = ref('')

	const instance = getCurrentInstance();

	onMounted(() => {
		getMenuItemTop();
	});

	const swichMenu = async (index : number) => {
		if (arr.value.length === 0) {
			await getMenuItemTop();
		}
		if (index === current.value) return;
		scrollRightTop.value = oldScrollTop.value;
		// 异步更新后使用 nextTick 确保能够正确获取最新的 DOM
		await new Promise<void>((resolve) => {
			setTimeout(() => {
				scrollRightTop.value = arr.value[index];
				current.value = index;
				leftMenuStatus(index);
				resolve();
			}, 0);
		});
	};

	const getElRect = (elClass : string, dataVal : string) => {
		const query = uni.createSelectorQuery().in(instance);
		query.select('.' + elClass).boundingClientRect((res) => {
			if (!res) {
				setTimeout(() => {
					getElRect(elClass, dataVal);
				}, 10);
				return;
			}
			instance.ctx[dataVal] = res.height;
		}).exec();
	};

	const observer = () => {
		tabbar.forEach((val, index) => {
			let observer = uni.createIntersectionObserver(this);
			observer.relativeTo('.right-box', { top: 0 }).observe('#item' + index, (res) => {
				if (res.intersectionRatio > 0) {
					let id = Number(res.id.substring(4));
					leftMenuStatus(id);
				}
			});
		});
	};

	const leftMenuStatus = (index : number) => {
		current.value = index;
		if (menuHeight.value == 0 || menuItemHeight.value == 0) {
			getElRect('menu-scroll-view', 'menuHeight');
			getElRect('u-tab-item', 'menuItemHeight');
		}
		scrollTop.value = index * menuItemHeight.value + menuItemHeight.value / 2 - menuHeight.value / 2;
	};

	const getMenuItemTop = () => {
		let selectorQuery = uni.createSelectorQuery();
		selectorQuery.selectAll('.class-item').boundingClientRect((rects) => {
			if (!rects.length) {
				setTimeout(() => {
					getMenuItemTop();
				}, 10);
				return;
			}
			rects.forEach((rect, index) => {
				arr.value.push(rect.top - rects[0].top);
			});
		}).exec();
	};

	const rightScroll = async (e : any) => {
		oldScrollTop.value = e.detail.scrollTop;
		if (arr.value.length === 0) {
			await getMenuItemTop();
		}
		if (timer) return;
		if (!menuHeight.value) {
			getElRect('menu-scroll-view', 'menuHeight');
		}
		setTimeout(() => {
			timer = null;
			let scrollHeight = e.detail.scrollTop + menuHeight.value / 2;
			for (let i = 0; i < arr.value.length; i++) {
				let height1 = arr.value[i];
				let height2 = arr.value[i + 1];
				if (!height2 || (scrollHeight >= height1 && scrollHeight < height2)) {
					leftMenuStatus(i);
					return;
				}
			}
		}, 10);
	};

	onBeforeUnmount(() => {
		if (timer) clearTimeout(timer);
	});
</script>

<style lang="scss" scoped>
	.u-wrap {
		height: calc(100vh);
		/* #ifdef H5 */
		height: calc(100vh - var(--window-top));
		/* #endif */
		display: flex;
		flex-direction: column;
	}

	.u-search-box {
		padding: 18rpx 30rpx;
	}

	.u-menu-wrap {
		flex: 1;
		display: flex;
		overflow: hidden;
	}

	.u-search-inner {
		background-color: rgb(234, 234, 234);
		border-radius: 100rpx;
		display: flex;
		align-items: center;
		padding: 10rpx 16rpx;
	}

	.u-search-text {
		font-size: 26rpx;
		color: $u-tips-color;
		margin-left: 10rpx;
	}

	.u-tab-view {
		width: 200rpx;
		height: 100%;
	}

	.u-tab-item {
		height: 110rpx;
		background: #f6f6f6;
		box-sizing: border-box;
		display: flex;
		align-items: center;
		justify-content: center;
		font-size: 26rpx;
		color: #444;
		font-weight: 400;
		line-height: 1;
	}

	.u-tab-item-active {
		position: relative;
		color: #000;
		font-size: 30rpx;
		font-weight: 600;
		background: #fff;
	}

	.u-tab-item-active::before {
		content: "";
		position: absolute;
		border-left: 4px solid $u-primary;
		height: 32rpx;
		left: 0;
		top: 39rpx;
	}

	.u-tab-view {
		height: 100%;
	}

	.right-box {
		background-color: rgb(250, 250, 250);
	}

	.page-view {
		padding: 16rpx;
	}

	.class-item {
		margin-bottom: 30rpx;
		background-color: #fff;
		padding: 16rpx;
		border-radius: 8rpx;
	}

	.class-item:last-child {
		min-height: 100vh;
	}

	.item-title {
		font-size: 26rpx;
		color: $u-main-color;
		font-weight: bold;
	}

	.item-menu-name {
		font-weight: normal;
		font-size: 24rpx;
		color: $u-main-color;
	}

	.item-container {
		display: flex;
		flex-wrap: wrap;
	}

	.thumb-box {
		width: 33.333333%;
		display: flex;
		align-items: center;
		justify-content: center;
		flex-direction: column;
		margin-top: 20rpx;
	}

	.item-menu-image {
		width: 120rpx;
		height: 120rpx;
	}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/165993.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】-进程间通信-命名管道文件(没有关系的进程间进行通信),以及写一个日志模板

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法&#x1f384; 如 果 你 …

mysql数据库【进阶篇】

1.存储引擎 1.1 mysql的体系结构 连接层&#xff1a;最上层是一些客户端和链接服务&#xff0c;主要完成- -些类似于连接处理、授权认证、及相关的安全方案。服务器也会为安全接入的每个客户端验证它所具有的操作权限。服务层&#xff1a;第二层架构主要完成大多数的核心服务功…

【教学类-06-06】20231118 (55格版)X以内加法、减法、加减混合题

背景需求 1、长期做手工制作&#xff0c;常规管理难以控制 优势&#xff1a; 1、幼儿创作热情高涨&#xff0c;发明的新玩具多 2、互助观摩&#xff0c;进一步模仿、创作作品 3、互动游戏兴趣浓厚&#xff0c;语言交流踊跃&#xff0c; 劣势&#xff1a; 1、纸条碎片多&…

深入流行推荐引擎3:Spotify音乐推荐系统

深入流行推荐引擎3&#xff1a;Spotify音乐推荐系统 Spotify音乐推荐系统通过矩阵分解发现每周&#xff08;Discover Weekly via Matrix Factorization&#xff09;Discover Weekly 如何运作&#xff1f;&#xff08;How Discover Weekly Works?&#xff09;矩阵分解&#xff…

【IPC】 共享内存

1、概述 共享内存允许两个或者多个进程共享给定的存储区域。 共享内存的特点 1、 共享内存是进程间共享数据的一种最快的方法。 一个进程向共享的内存区域写入了数据&#xff0c;共享这个内存区域的所有进程就可以立刻看到 其中的内容。 2、使用共享内存要注意的是多个进程…

使用持久卷部署 WordPress 和 MySQL

&#x1f5d3;️实验环境 OS名称Microsoft Windows 11 家庭中文版系统类型x64-based PCDocker版本Docker version 24.0.6, build ed223bcminikube版本v1.32.0 &#x1f587;️创建 kustomization.yaml 你可以通过 kustomization.yaml 中的生成器创建一个 Secret存储密码或密…

Android问题笔记四十六:解决open failed: EACCES (Permission denied) 问题

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列点击跳转>ChatGPT和AIGC &#x1f449;关于作者 专…

Jmeter性能实战之分布式压测

JMeter分布式执行原理 1、JMeter分布式测试时&#xff0c;选择其中一台作为调度机(master)&#xff0c;其它机器作为执行机(slave)。 2、执行时&#xff0c;master会把脚本发送到每台slave上&#xff0c;slave 拿到脚本后就开始执行&#xff0c;slave执行时不需要启动GUI&…

深度学习YOLO抽烟行为检测 - python opencv 计算机竞赛

文章目录 1 前言1 课题背景2 实现效果3 Yolov5算法3.1 简介3.2 相关技术 4 数据集处理及实验5 部分核心代码6 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习YOLO抽烟行为检测 该项目较为新颖&#xff0c;适合作为竞赛课…

Parity Game——种类并查集、权值并查集、离散化

题目描述 思路 怎么得到这个序列中每一段的关系&#xff1f; 我们可以把这个只包含0和1的序列看作一个数组&#xff0c;0表示当前位置为0&#xff0c;1表示当前位置为1&#xff0c;利用前缀和的性质可以知道某一段中所包含的1的数量sum1 a[r] - a[l-1] 如果sum1为偶数&…

Rust开发——切片(slice)类型

1、什么是切片 在 Rust 中&#xff0c;切片&#xff08;slice&#xff09;是一种基本类型和序列类型。在 Rust 官方文档中&#xff0c;切片被定义为“对连续序列的动态大小视图”。 但在rust的Github 源码中切片被定义如下&#xff1a; 切片是对一块内存的视图&#xff0c;表…

如何隐藏Selenium特征实现自动化网页采集

Selenium是一个流行的自动化网页测试工具&#xff0c;可以通过模拟用户在Chrome浏览器中的操作来完成网站的测试。然而&#xff0c;有些网站会检测浏览器是否由Selenium驱动&#xff0c;如果是&#xff0c;就会返回错误的结果或拒绝访问。为了避免这种情况&#xff0c;我们需要…

多线程编程

1 线程的使用 1.1 为什么要使用多线程 在编写代码时&#xff0c;是否会遇到以下的场景会感觉到难以下手&#xff1f; 要做 2 件事&#xff0c;一件需要阻塞等待&#xff0c;另一件需要实时进行。例如播放器&#xff1a;一边在屏幕上播放视频&#xff0c;一边在等待用户的按…

中间件安全:Apache 目录穿透.(CVE-2021-41773)

中间件安全&#xff1a;Apache 目录穿透.&#xff08;CVE-2021-41773&#xff09; Apache 的 2.4.49、2.4.50 版本 对路径规范化所做的更改中存在一个路径穿越漏洞&#xff0c;攻击者可利用该漏洞读取到Web目录外的其他文件&#xff0c;如系统配置文件、网站源码等&#xff0c…

Polygon zkEVM协议治理、升级及其流程

1. 引言 随着Polygon社区开发者和内部团队的测试深入&#xff0c;当前版本的Polygon zkEVM不可避免地需更新和某些升级。 为激励开发者对Polygon zkEVM做battle-test&#xff0c;已启动了bug-bounty&#xff1a; Rewards by Threat Level 由于zk-Rollup生态系统还处于萌芽阶…

算法设计与分析复习--贪心(二)

文章目录 上一篇哈夫曼编码单源最短路最小生成树Kruskal算法Prim算法 多机调度问题下一篇 上一篇 算法设计与分析复习–贪心&#xff08;一&#xff09; 哈夫曼编码 产生这种前缀码的方式称为哈夫曼树 哈夫曼树相关习题AcWing 148. 合并果子 #include <iostream> #inc…

LDO线性稳压器要不要并联二极管?

昨天介绍过了LDO是什么东西&#xff0c;那么对于它的应用场景是怎么的呢&#xff1f;LDO要不要并联二极管呢&#xff1f; 一般来说&#xff0c;LDO是不需要并联二极管的。 看下图第一个是典型电路&#xff0c;第二个是带可调节电压功能的LDO典型电路&#xff0c;从图里就可以…

设计模式-组合模式-笔记

“数据结构”模式 常常有一些组件在内部具有特定的数据结构&#xff0c;如果让客户程序依赖这些特定数据结构&#xff0c;将极大地破坏组件的复用。这时候&#xff0c;将这些特定数据结构封装在内部&#xff0c;在外部提供统一的接口&#xff0c;来实现与特定数据结构无关的访…

一起Talk Android吧(第五百五十四回:分享一个Retorfit使用错误的案例)

文章目录 1. 案例场景2. 案例现象3. 原因分析和解决方案3.1 原因分析3.2 解决方案4. 经验总结各位看官们大家好,上一回中咱们说的例子是"解析Retrofit返回的数据",本章回中将分享一个 Retrofit使用错误的案例。闲话休提,言归正转,让我们一起Talk Android吧! 1. …

三层交换机实现不同VLAN间通讯

默认时&#xff0c;同一个VLAN中的主机才能彼此通信&#xff0c;那么交换机上的VLAN用户之间如何通信&#xff1f; 要实现VLAN之间用户的通信&#xff0c;就必须借助路由器或三层交换机来完成。 下面以三层交换机为例子说明&#xff1a; 注意&#xff1a; 1.交换机与三层交换…