以下完整代码拷贝直接可以使用, 替换一下 tabr数组里面的图片就可以了


<template>
	<view class="">
		<view class="u-wrap">
			<view class="u-menu-wrap">
				<scroll-view 
					scroll-y 
					scroll-with-animation 
					class="u-tab-view menu-scroll-view" 
					:scroll-top="scrollTop"
					>
					<view v-for="(item,index) in tabbar" :key="index" class="u-tab-item"
						:class="[optIndex == 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 
					:scroll-into-view="itemId"
					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 v-if="item1.icon != ''" class="item-menu-image" :src="item1.icon" mode=""></image>

									<!-- <view class="item-menu-name">{{item1.name}}</view> -->
									<view class="contetn-box">
										  <view class="item-menu-name">{{item1.name}}</view> 
										   <view class="info">
										   	  味道很好吃
										   </view>
										   <view class="price-box">
										   	   <view class="price">
										   	   	¥66
										   	   </view>
											   <!-- <order-number-box  v-model="item.cat"   /> -->
										   </view>
									</view>
								</view>
							</view>
						</view>
					</view>
				</scroll-view>
			</view>
		</view>

	</view>
</template>

<script setup>
	  import { onLoad, onReachBottom, onPullDownRefresh, onShow, onHide, onPageScroll } from '@dcloudio/uni-app';
	  import { ref } from 'vue';
	
	    const optIndex = ref(0); //左边菜单值,同时也为上一个页面传过来的值(传过来精确在第几行并使样式为active)
	    const itemId = ref(''); // 右边scroll-view用于滚动的id(自动滚动定位左边)
		const scrollTop = ref(0); //tab标题的滚动条位置
		const oldScrollTop = ref(0);// tab标题的滚动条旧位置
		 //const current = ref(0) // 预设当前项的值
		const menuHeight = ref(0); // 左边菜单的高度
		const menuItemHeight = ref(0);// 左边菜单item的高度
	    const arr = reactive([]);// 储存距离顶部高度的数组
		const scrollRightTop = ref(0);// 右边栏目scroll-view的滚动条高度
	    const timer = ref(null);// 定时器
		const dataVal = ref()
	   //商品分类数据 
	    const tabbar = ref([
			      {
						"name": "白兰地",
						"foods": [{
								"cat": 383,
								"name": "蔬菜",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "蔬菜"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							}
						]
					},
					{
						"name": "香槟系列",
						"foods": [{
								"cat": 388,
								"name": "禽类",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "禽类"
							},
							{
								"cat": 389,
								"name": "畜类",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "畜类"
							},
							{
								"cat": 391,
								"name": "蛋类",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "蛋类"
							},
							{
								"cat": 390,
								"name": "水产",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水产"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							}
						]
					},
					{
						"name": "东南亚美食",
						"foods": [{
								"cat": 393,
								"name": "米面粮油",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "米面粮油"
							},
							{
								"cat": 394,
								"name": "坚果干果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "坚果干果"
							},
							{
								"cat": 395,
								"name": "加工食品",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "加工食品"
							},
							{
								"cat": 396,
								"name": "茶烟酒",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "茶烟酒"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							}
						]
					},
					{
						"name": "少年甜品",
						"foods": [{
								"cat": 398,
								"name": "鲜花盆景",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "鲜花盆景"
							},
							{
								"cat": 399,
								"name": "果树苗",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "果树苗"
							},
							{
								"cat": 400,
								"name": "蔬瓜种子",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "蔬瓜种子"
							},
							{
								"cat": 401,
								"name": "经济作物",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "经济作物"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							}
						]
					},
					{
						"name": "暖心服务",
						"foods": [{
								"cat": 403,
								"name": "全草类",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "全草类"
							},
							{
								"cat": 405,
								"name": "根茎皮叶花",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "根茎皮叶花"
							},
							{
								"cat": 406,
								"name": "滋补品类",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "滋补品类"
							},
							{
								"cat": 404,
								"name": "果实籽仁类",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "果实籽仁类"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							}
						]
					},
					{
						"name": "团购套餐",
						"foods": [{
								"cat": 434,
								"name": "包装",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "包装"
							},
							{
								"cat": 435,
								"name": "安全溯源",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "安全溯源"
							},
							{
								"cat": 436,
								"name": "农用百货",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "农用百货"
							},
							{
								"cat": 437,
								"name": "仓储物流",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "仓储物流"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							},
							{
								"cat": 385,
								"name": "水果",
								"icon": "https://i-blog.csdnimg.cn/direct/1d476d2952364d98a4aba837d1b0b463.jpeg",
								"key": "水果"
							}
						]
					},
				
				])
				
				
		
		onLoad( (opt) => {
		   console.log(opt.index);
		   // 判断是否有传过来的 index ,有就赋值itemId,并激活optIndex
		   if (opt.index) {
		     itemId.value = "item" + opt.index;
		     optIndex.value = opt.index;
		   }
		   // 若获取数据后的情况下定位不起作用,就加定时器
		   //if(opt.index){
		   //	setTimeout(()=>{
		   //		itemId.value = "item" + opt.index;
		   //		optIndex.value = opt.index;
		   //	},1000)
		   //}
		});
		
	
	    // Handle the ready event
	     onReady (()=> {
			 getMenuItemTop()
		 })
		 
	   /**
	    * 获取一个目标元素的高度
	    * @elClass 元素的类名
	    * @dataVal 储存高度的对象
	    */ 
	  const getElRect = (elClass, pdataVal) => {
	    // console.log(elClass, 'elClass1');	
	    // console.log(pdataVal, 'dataVal2');
	    return new Promise((resolve, reject) => {
	      const query = uni.createSelectorQuery().in(this);
	      // console.log(query, 'query66');
	      query.select('.' + elClass).fields({ size: true }, (res) => {
	        // console.log(res, 'res.fields');
	        if (!res) {
	          setTimeout(() => {
	            getElRect(elClass, dataVal); // 递归调用
	          }, 10);
	          return;
	        }
	        dataVal.value =  res.height;  
	        resolve();
			
	      }).exec();
	    });
	  };
	
	    // Method to get the menu item top values
	    const getMenuItemTop = () => {
	      new Promise(resolve => {
	        let selectorQuery = uni.createSelectorQuery();
	        selectorQuery.selectAll('.class-item').boundingClientRect((rects) => {
				// 如果节点尚未生成,rects值为[](因为用selectAll,所以返回的是数组),循环调用执行
	          if (!rects.length) {
	            setTimeout(() => {
	              getMenuItemTop();
	            }, 10);
	            return;
	          }
	          rects.forEach((rect) => {
				  // 视情况而定,这里减去rects[0].top,是因为第一项顶部可能不是贴到导航栏(比如有个搜索框的情况)
				  // this.arr.push(rect.top - rects[0].top);
	            arr.push(rect.top - rects[0].top);
	            resolve();
	          });
	        }).exec();
	      });
	    };
	
	    /**
	     * 观测元素相交状态
	     * 检测右边scroll-view的id为itemxx的元素与right-box的相交状态
	     * 如果跟.right-box底部相交,就动态设置左边栏目的活动状态
	     */
	    const observer = async () => {
	      tabbar.map((val, index) => {
	        let observer = uni.createIntersectionObserver(this);
	        observer.relativeTo('.right-box', { top: 0 }).observe('#item' + index, res => {
	          if (res.intersectionRatio > 0) {
	            let id = res.id.substring(4);
	            leftMenuStatus(id);
	          }
	        });
	      });
	    };
	
	    /**
	     * 设置左边菜单的滚动状态
	     * @index 传入的 ID
	     */
	    const leftMenuStatus = async (index) => {
	      optIndex.value = index;
		  // 如果为0,意味着尚未初始化
	      if (menuHeight.value === 0 || menuItemHeight.value === 0) {
	        await getElRect('menu-scroll-view', 'menuHeight');
	        await getElRect('u-tab-item', 'menuItemHeight');
	      }
		  	// 将菜单活动item垂直居中
	      scrollTop.value = index * menuItemHeight.value + menuItemHeight.value / 2 - menuHeight.value / 2;
	    };
	
	    /**
	     * 点击左边的栏目切换
	     * @index 传入的 ID
	     */
	    const swichMenu = async (index) => {
	      if (arr.length === 0) {
	        await getMenuItemTop();
	      }
	      scrollRightTop.value = oldScrollTop.value;
	      nextTick(function() {
	        scrollRightTop.value = arr[index];
	        optIndex.value = index;
	        leftMenuStatus(index);
	      });
	    };
	
	    /**
	     * 右边菜单滚动
	     * 如果不存在height2,意味着数据循环已经到了最后一个,设置左边菜单为最后一项即可
	     */
	    const rightScroll = async (e) => {
	      oldScrollTop.value = e.detail.scrollTop;
	      if (arr.length === 0) {
	        await getMenuItemTop();
	      }
	      if (timer.value) return;
	      if (!menuHeight.value) {
	        await getElRect('menu-scroll-view', 'menuHeight');
	      }
	      setTimeout(() => {//节流
	        timer.value = null;
			// scrollHeight为右边菜单垂直中点位置
			// let scrollHeight = e.detail.scrollTop + this.menuHeight / 2;
			// scrollHeight为右边菜单头部位置
	        let scrollHeight = e.detail.scrollTop + 20;
	        for (let i = 0; i < arr.length; i++) {
	          let height1 = arr[i];
	          let height2 = arr[i + 1];
	          if (!height2 || scrollHeight >= height1 && scrollHeight < height2) {
	            leftMenuStatus(i);
	            return;
	          }
	        }
	      }, 10);
	    };

</script>

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

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

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

	.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: 28rpx;
		color: #333;
		font-weight: 400;
		line-height: 1;
	}

	.u-tab-item-active {
		position: relative;
		background: linear-gradient(to right,#d9ffd9,#f5f5f5) !important;
		border-left: .3125rem solid #7acc7a;
		font-size: 28rpx;
		font-weight: bold;
		background: #fff;
		z-index: 1;
	}

	.u-tab-view {
		height: 100%;
		    background-color: #F9F9F9;
	}


	.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: 28rpx;
		color: #333333;
		font-weight: bold;
	}

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

	.thumb-box {
		width: 100%;
		display: flex;
		margin-top: 20rpx;
	}
	.contetn-box { 
		margin-left: 24rpx;
	    flex: 1;
		.item-menu-name {
			margin-top: 8rpx;
			font-weight: normal;
			font-size: 28rpx;
			color: #333333;
		}
		.info {
			margin: 30rpx 0 40rpx 0;
			font-size: 24rpx;
			color: #666;
		}
		.price-box {
			display: flex;
			align-items: center;
			justify-content: space-between;
		}
	} 

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

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐